gpt4 book ai didi

android - CoroutineScope - CompletableDeferred 取消

转载 作者:行者123 更新时间:2023-11-29 23:30:31 24 4
gpt4 key购买 nike

关于这个话题我有两个问题。我将在 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
}

最佳答案

您应该避免使用第一种方法,因为它会阻塞线程池中的线程。使用第二种方法,您可以双向传播取消。如果你取消 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 路线可能是转移注意力。如果你要取消它,根本原因是你要从你正在做的整个任务中解脱出来。您应该取消它运行的整个协程。如果您正确实现 structured concurrency ,如果您的 Activity 被销毁,一切都会自动发生。

所以我的建议是使用这段代码:

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 是您的 Activity ,它也是一个 CoroutineScope

关于android - CoroutineScope - CompletableDeferred 取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52774588/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com