关于这个话题,我有两个问题。我将在android中使用这些用例类,并尝试实现类似于这个https://www.youtube.com/watch?v=Sy6ZdgqrQp0的体系结构,但我需要一些答案。
1)我有一个带有异步构建器的延迟,当我取消作业时,其他链也被取消了。此代码打印“呼叫取消”。但我不确定我做得对不对。
fun main(args: Array<String>) = runBlocking<Unit> {
val job = GlobalScope.launch {
println(getUser())
}
job.cancelAndJoin()
}
suspend fun getUser() = getUserDeferred().await()
suspend fun getUserDeferred() = coroutineScope {
val request = Request.Builder()
.url("https://jsonplaceholder.typicode.com/users")
.build()
val call = OkHttpClient().newCall(request)
val deferred = async(Dispatchers.IO) {
val body = call.execute()
body.body()?.string() ?: ""
}
deferred.invokeOnCompletion {
if (deferred.isCancelled) {
println("Call cancelled")
call.cancel()
}
}
deferred
}2)我想不出取消这个计划的办法。我想在retrofit2调用适配器中使用这一点,是否有更好的方法来处理这种情况。
fun main(args: Array<String>) = runBlocking<Unit> {
val job = GlobalScope.launch {
println(getUser1())
}
job.cancelAndJoin()
}
suspend fun getUser1() = getUser1Deferred().await()
fun getUser1Deferred(): Deferred<String> {
val request = Request.Builder()
.url("https://jsonplaceholder.typicode.com/users")
.build()
val call = OkHttpClient().newCall(request)
val deferred = CompletableDeferred<String>()
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
deferred.complete("Error")
}
override fun onResponse(call: Call, response: Response) {
deferred.complete(response.body()?.string() ?: "Error")
}
})
deferred.invokeOnCompletion {
if (deferred.isCancelled) {
println("Call cancelled")
call.cancel()
}
}
return deferred
}发布于 2018-10-12 08:36:56
您应该避免使用第一种方法,因为它会阻塞线程池中的线程。使用第二种方法,您可以通过两种方式传播取消。如果您取消了Deferred,它将取消调用,如果调用失败,它将取消Deferred,除非它得到异常。
fun getUserAsync(): Deferred<String> {
val call = OkHttpClient().newCall(Request.Builder()
.url("https://jsonplaceholder.typicode.com/users")
.build())
val deferred = CompletableDeferred<String>().apply {
invokeOnCompletion {
if (isCancelled) {
call.cancel()
}
}
}
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
deferred.complete(response.body()?.string() ?: "Error")
}
override fun onFailure(call: Call, e: IOException) {
deferred.cancel(e)
}
})
return deferred
}然而,走Deferred路线可能是一条红鱼。如果你要取消它,最根本的原因是你要放弃你正在做的全部任务。你应该取消它运行的整个协同线。如果您正确地实现了结构化并发,那么当您的活动被破坏时,一切都会自动发生。
所以我的建议是使用以下代码:
suspend fun getUser() = suspendCancellableCoroutine<String> { cont ->
val call = OkHttpClient().newCall(Request.Builder()
.url("https://jsonplaceholder.typicode.com/users")
.build())
cont.invokeOnCancellation {
call.cancel()
}
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
cont.resume(response.body()?.string() ?: "Error")
}
override fun onFailure(call: Call, e: IOException) {
cont.resumeWithException(e)
}
})
}如果您绝对需要Deferred,因为您是在后台并发运行它,那么使用上面的内容是很容易的:
val userDeferred = this.async { getUser() }假设this是您的活动,它也是一个CoroutineScope。
发布于 2019-03-27 17:55:14
第二种情况不是取消的原因是因为您使用的是CompletableDeferred。它不是作为协同线启动的,也不是你父母协同机制的孩子。因此,如果您取消父级,它将不会取消延迟。
在第一种情况下,它可以工作,因为async启动了一个新的子协同线,它是链接到父节点的。当你取消任何一个,他们都会被取消。
为了将Deferred链接到父作业,需要引用它并使用invokeOnCompletion
var deferred : Deferred<Void>? = null
launch {
deferred = retroService.someDeferredCall()
deferred.await()
}.invokeOnCompletion {
//job was cancelled. Probably activity closing.
if(it is CancellationException) {
deferred?.let { it.cancel() }
}
}不是很漂亮,但应该能把工作做完。
https://stackoverflow.com/questions/52774588
复制相似问题