android - 在suspendCancellableCoroutine中取消回调
问题描述
我在 suspendCancellableCoroutine 中包装了一个回调,以将其转换为挂起函数:
suspend fun TextToSpeech.speakAndWait(text: String) : Boolean {
val uniqueUtteranceId = getUniqueUtteranceId(text)
speak(text, TextToSpeech.QUEUE_FLUSH, null, uniqueUtteranceId)
return suspendCancellableCoroutine { continuation ->
this.setOnUtteranceProgressListener(object : JeLisUtteranceProgressListener() {
override fun onDone(utteranceId: String?) {
if(utteranceId == uniqueUtteranceId) {
Timber.d("word is read, resuming with the next word")
continuation.resume(true)
}
}
})
}
}
我用片段的生命周期范围协程范围调用这个函数,我假设它在片段被销毁时被取消。但是,LeakCanary 报告说我的片段因为这个监听器而泄漏,我用日志验证了即使在协程被取消后也调用了回调。
所以似乎用suspendCancellableCoroutine而不是suspendCoroutine包装并不足以取消回调。我想我应该主动检查作业是否处于活动状态,但是如何?我尝试coroutineContext.ensureActive()
检查coroutineContext.isActive
回调内部,但 IDE 给出错误提示“只能在协程主体内调用暂停函数”我还能做些什么来确保在作业被取消时它不会恢复?
解决方案
如果您想删除JeLisUtteranceProgressListener
无论结果如何(成功、取消或其他错误),您都可以使用经典的 try/finally 块:
suspend fun TextToSpeech.speakAndWait(text: String) : Boolean {
val uniqueUtteranceId = getUniqueUtteranceId(text)
speak(text, TextToSpeech.QUEUE_FLUSH, null, uniqueUtteranceId)
return try {
suspendCancellableCoroutine { continuation ->
this.setOnUtteranceProgressListener(object : JeLisUtteranceProgressListener() {
override fun onDone(utteranceId: String?) {
if(utteranceId == uniqueUtteranceId) {
Timber.d("word is read, resuming with the next word")
continuation.resume(true)
}
}
})
} finally {
this.setOnUtteranceProgressListener(null)
}
}
推荐阅读
- json - Jmeter JSONAssertion 失败消息
- excel - 使用具有重复列的powershell循环遍历excel数据
- python - JupyterLab:您的浏览器不支持 WebGL
- batch-file - 当远程主机关闭连接时,有没有办法在 Windows ssh 中跳过“按任意键继续”?
- spring - 使用 Spring Data Reactive Elasticsearch 排序
- c - 使用c中的函数从排序数组中查找中位数
- c++ - 如何在 cmake 中包含适用于 g++ 或反之亦然的库
- php - 无法连接到 Apache Web 服务器
- windows - 我需要知道如何批量回显嵌套变量
- android - Android 应用程序 ImageView.Gone 在设备上不一致