【发布时间】:2021-10-18 05:51:24
【问题描述】:
我在运行协程时遇到奇怪的锁定(冻结)。有时它工作得很好,有时它会等待并在很长一段时间后继续运行(或根本不运行)。我不知道如果我的设置不正确,存在一些竞争条件,或者我误解了应该如何使用协程。应用程序本身不会冻结或崩溃,它只是协程停止/暂停执行。
例如,在这个位中,scope.launch 有时不会继续执行到billingClientDeferred.await()
override suspend fun getPurchases(): Result<List<Purchase>> = suspendCoroutine { continuation ->
scope.launch {
billingClientDeferred.await().success { client ->
client.queryPurchasesAsync(BillingClient.SkuType.SUBS) Subs@{ billingResultSubs, purchasesSubs ->
if (billingResultSubs.responseCode != BillingClient.BillingResponseCode.OK) {
continuation.resume(Result.Failure.Unknown())
return@Subs
}
continuation.resume(Result.Success(purchasesSubs))
}
}
}
}
scope 声明为:
private val scope = CoroutineScope(Job() + Dispatchers.Default)
然后从WalletManager调用
override suspend fun verifyProducts(): Result<Unit> = billingProvider.getPurchases()
.successSuspend { purchases ->
purchases.forEach {
activatePurchase(it)
}
}.map { }
到底是从ViewModel这样调用的
override fun verify() {
viewModelScope.launch {
userSupervisor.walletManager.mapResult {
it.verifyProducts()
}
}
}
我猜我正在使用的调度程序和范围的组合存在一些问题。我尝试了不同的事情,Dispatchers.Default、Dispatchers.Main,符合CoroutineScope 的类,使用全局范围,但我总是遇到一些我不完全理解的线程/锁定问题。
【问题讨论】:
-
你在suspendCoroutine里面启动一个新协程的具体原因是什么,你清楚地理解suspendCoroutine函数的用例吗?
-
因为我在内部使用了基于回调的函数
client.queryPurchasesAsync和基于协程的billingClientDeferred.await()。我可以提取queryPurchasesAsync将其转换为挂起函数,然后就不需要在getPurchases中使用scope.launch。这样做是不好的做法吗?这可能是我的问题的原因吗? -
这是一种不好的做法,因为您的协程在父子关系中不再相关。您使用 viewModelScope 触发了您的根协同程序,并且在该协同程序中您使用您定义的范围触发了另一个协同程序。除非您自己取消该范围,否则当取消 viewModelScope 时,它不会取消使用您的范围触发的协程。 suspendCoroutine 正在桥接基于回调的代码和基于协程的代码。转换需要转换的任何内容以避免在suspendCoroutine中触发新的协程。
标签: android kotlin kotlin-coroutines coroutine