bj0
02/14/2018, 9:14 PMCompletableDeferred
was completely internal, I was using return deferred.await()
and object.onCallback {deferred.complete(it)}
dave08
02/15/2018, 3:46 AMinvokeOnCompletion
and check the`isCancelled` property on the CancellableContinuation
provided... see https://github.com/Kotlin/kotlinx.coroutines/blob/master/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.ktdave08
02/15/2018, 3:47 AMbj0
02/15/2018, 6:31 AMCompletableDeferred
, but I don't see what invokeOnCompletion
has to do with it. Using a Future
is effectively the same thing as using a CompletableDeferred
dave08
02/15/2018, 7:19 AMbj0
02/15/2018, 4:42 PMvar deferred: CompletableDeferred<Item>? = null
suspend fun getItem(): Item {
deferred = CompletableDeferred<Item>
someObject.onCallback { deferred.complete(it) }
return deferred!!.await()
}
fun cancelGet() = deferred?.cancel() ?: false
bj0
02/15/2018, 4:44 PMcancelGet
can be called from another source (like a user hitting the back button)dave08
02/15/2018, 4:46 PMbj0
02/15/2018, 4:50 PMlaunch
, but another suspend fun
bj0
02/15/2018, 4:51 PMdave08
02/15/2018, 4:51 PMdave08
02/15/2018, 4:52 PMbj0
02/15/2018, 4:52 PMdave08
02/15/2018, 4:53 PMbj0
02/15/2018, 4:54 PMdave08
02/15/2018, 5:01 PMbj0
02/15/2018, 5:01 PMvar activeCont: CancellableContinuation<Item>? = null
suspend fun getItem() = suspendCancellableCoroutine<Item> { cont ->
someObject.onCallback { cont.complete(it) }
activeCont = cont
}
fun cancelGet() = activeCont?.cancel() ?: false
bj0
02/15/2018, 5:03 PMdave08
02/15/2018, 5:07 PMdave08
02/15/2018, 5:09 PMclass XmlRpcCoroutineClientImpl(override val client: XmlRpcClient): XmlRpcCoroutineClient {
override suspend fun <T> awaitExecute(pRequest: XmlRpcRequest): T? =
suspendCancellableCoroutine {
client.executeAsync(pRequest, object: AsyncCallback {
override fun handleResult(pRequest: XmlRpcRequest?, pResult: Any) {
<http://logger.info|logger.info>("Request '$pRequest' succeeded: {}", pResult.toString())
it.resume(pResult as? T)
}
override fun handleError(pRequest: XmlRpcRequest?, pError: Throwable) {
logger.error("Request '$pRequest' failed: ", pError)
it.resumeWithException(pError)
}
})
}
}
dave08
02/15/2018, 5:10 PMxmlRpcClient.awaitExecutes(it, Array<Any>::class.java)
dave08
02/15/2018, 5:10 PMdave08
02/15/2018, 5:11 PMbj0
02/15/2018, 5:13 PMbj0
02/15/2018, 5:16 PMlaunch
at the callsitedave08
02/15/2018, 5:17 PMbj0
02/15/2018, 5:18 PMdave08
02/15/2018, 5:24 PMvar currItemGetterJob: Job? = null
// In the actor, simplified...
currItemGetterJob = launch { getItem() }
// In cancel button handler
currItemGetterJob.cancel()
Just make sure that you don't accidentally assign a new job before cancelling the old one...bj0
02/15/2018, 5:30 PMgetItem
is to the callsite. And in my case the android back button is actually handled in a parent class so it would be more difficult. Plus, if I use the continuation for cancellation like in that last snippet I posted, than I don't have to create any extra jobs, it just cancels the calling scope (as if I just threw CancellationException
at the callsite)dave08
02/15/2018, 6:07 PMfun getItem() = async {}
then await for the deferred or cancel it... I think that you're using internal api to do end user work... you might run into pitfalls that were already taken care of for you... you can run 10000 launches and its still very light...bj0
02/15/2018, 6:20 PMbj0
02/15/2018, 6:24 PMsuspendCancellableCoroutine
, one callback just happens to signal cancellation through an external function call.