我有一个可以保存大文件的文件管理类。文件管理器类是一个应用程序单例,因此它比我的 UI 类长。我的 Activity/Fragment 可以从协程调用文件管理器的 save
挂起函数,然后在 UI 中显示成功或失败。例如:
//In MyActivity:
private fun saveTheFile() = lifecycleScope.launch {
try {
myFileManager.saveBigFile()
myTextView.text = "Successfully saved file"
} catch (e: IOException) {
myTextView.text = "Failed to save file"
}
}
//In MyFileManager
suspend fun saveBigFile() {
//Set up the parameters
//...
withContext(Dispatchers.IO) {
//Save the file
//...
}
}
这种方法的问题是我不希望在 Activity 完成时中止保存操作。如果在 withContext
block 开始之前 Activity 被销毁,或者如果 withContext
block 中有任何挂起点,那么保存将不会完成,因为协程将被取消.
我想要发生的是文件总是被保存。如果 Activity 仍然存在,那么我们可以在完成时显示 UI 更新。
我认为一种方法可能是像这样从挂起函数启动一个新的 coroutineScope
,但是当它的父作业被取消时,这个范围似乎仍然被取消了。
suspend fun saveBigFile() = coroutineScope {
//...
}
我认为另一种选择可能是使它成为一个常规函数,在它完成时更新一些 LiveData。 Activity 可以观察结果的实时数据,并且由于 LiveData 在销毁生命周期观察者时会自动删除它们,因此 Activity 不会泄露给 FileManager。如果可以代替上面那样复杂的事情,我想避免这种模式。
//In MyActivity:
private fun saveTheFile() {
val result = myFileManager.saveBigFile()
result.observe(this@MyActivity) {
myTextView.text = when (it) {
true -> "Successfully saved file"
else -> "Failed to save file"
}
}
}
//In MyFileManager
fun saveBigFile(): LiveData<Boolean> {
//Set up the parameters
//...
val liveData = MutableLiveData<Boolean>()
MainScope().launch {
val success = withContext(Dispatchers.IO) {
//Save the file
//...
}
liveData.value = success
}
return liveData
}
最佳答案
您可以用NonCancellable
包装您不想取消的位。
// May cancel here.
withContext(Dispatchers.IO + NonCancellable) {
// Will complete, even if cancelled.
}
// May cancel here.
关于android - 使协程的一部分继续取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60155439/