From d2732ba4c5327cafc019408ac16e265d6a0d29d1 Mon Sep 17 00:00:00 2001 From: Phill Date: Wed, 30 Sep 2020 11:48:00 +0100 Subject: [PATCH 1/2] feature: Coroutine Task Wrapper - Add extension functions to wrap Task in coroutine - Update libs --- build.gradle | 2 +- coroutines/README.md | 27 ++++++++++++++++ coroutines/build.gradle | 2 +- .../parse/coroutines/ParseTaskExtensions.kt | 31 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt diff --git a/build.gradle b/build.gradle index 55ee06677..586f69f2c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = "1.3.72" + ext.kotlin_version = "1.4.10" repositories { google() jcenter() diff --git a/coroutines/README.md b/coroutines/README.md index 9ba73e652..8e1fce730 100644 --- a/coroutines/README.md +++ b/coroutines/README.md @@ -72,6 +72,33 @@ launch { // Coroutine builder We can save, pinning and fetch parse objects use coroutines as well. +## Task Wrapper +Coroutine support can be provided as an extension method on any `Task`. For example: +```kotlin +suspend fun anonymousLogin() { + try { + val user = ParseAnonymousUtils.logInInBackground().suspendGet() + Timber.d("Logged in with user ${user.objectId}") + } catch (e: ParseException) { + Timber.e(e) + } +} +``` +Tasks with a Void results, ie. `Task` can be made into a `Completable`. +For example: +```kotlin +suspend fun updateUserLastLogIn() { + val user = ParseUser.getCurrentUser() + user.put("lastLoggedIn", System.currentTimeMillis()) + try { + user.saveInBackground().suspendRun() + Timber.d("user saved") + } catch (e: ParseException) { + Timber.e(it) + } +} +``` + ## Contributing When contributing to the `coroutines` module, please first consider if the extension function you are wanting to add would potentially be better suited in the main `parse` module. If it is something specific to Kotlin users or only useful in a Kotlin project, feel free to make a PR adding it to this module. Otherwise, consider adding the addition to the `parse` module itself, so that it is still usable in Java. diff --git a/coroutines/build.gradle b/coroutines/build.gradle index 64f3186d3..00e93ae2a 100644 --- a/coroutines/build.gradle +++ b/coroutines/build.gradle @@ -29,7 +29,7 @@ android { } ext { - coroutinesVersion = "1.3.3" + coroutinesVersion = "1.3.9" } dependencies { diff --git a/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt b/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt new file mode 100644 index 000000000..63c5698e5 --- /dev/null +++ b/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt @@ -0,0 +1,31 @@ +@file:JvmName("ParseTaskExtensions") + +package com.parse.coroutines + +import com.parse.boltsinternal.Task +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +@Suppress("BlockingMethodInNonBlockingContext") +suspend fun Task.suspendGet(dispatcher: CoroutineDispatcher = Dispatchers.IO) = withContext(dispatcher) { + suspendCoroutine { continuation -> + if (isFaulted) { + continuation.resumeWithException(error) + } + waitForCompletion() + } +} + +@Suppress("BlockingMethodInNonBlockingContext") +suspend fun Task.suspendRun(dispatcher: CoroutineDispatcher = Dispatchers.IO) = withContext(dispatcher) { + suspendCoroutine { continuation -> + if (isFaulted) { + continuation.resumeWithException(error) + } + waitForCompletion() + } +} + From 38997523f3ec08999545d972a4dcfdcef105c064 Mon Sep 17 00:00:00 2001 From: Phill Date: Wed, 30 Sep 2020 14:19:16 +0100 Subject: [PATCH 2/2] feature: Coroutine Task Wrapper - Suppress unused - Correct logic for background threading --- .../java/com/parse/coroutines/ParseTaskExtensions.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt b/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt index 63c5698e5..d6dff640f 100644 --- a/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt +++ b/coroutines/src/main/java/com/parse/coroutines/ParseTaskExtensions.kt @@ -1,4 +1,5 @@ @file:JvmName("ParseTaskExtensions") +@file:Suppress("unused") package com.parse.coroutines @@ -6,26 +7,29 @@ import com.parse.boltsinternal.Task import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine @Suppress("BlockingMethodInNonBlockingContext") suspend fun Task.suspendGet(dispatcher: CoroutineDispatcher = Dispatchers.IO) = withContext(dispatcher) { - suspendCoroutine { continuation -> + return@withContext suspendCoroutine { continuation -> + waitForCompletion() if (isFaulted) { continuation.resumeWithException(error) } - waitForCompletion() + continuation.resume(result) } } @Suppress("BlockingMethodInNonBlockingContext") suspend fun Task.suspendRun(dispatcher: CoroutineDispatcher = Dispatchers.IO) = withContext(dispatcher) { - suspendCoroutine { continuation -> + return@withContext suspendCoroutine { continuation -> + waitForCompletion() if (isFaulted) { continuation.resumeWithException(error) } - waitForCompletion() + continuation.resume(Unit) } }