[英]Run coroutine past viewModelScope lifecycle
我需要确保即使清除了viewModel
也会完成挂起功能。 例如,我的应用程序中有一个按钮,单击该按钮时会调用viewModel.addItem(item)
,然后该函数会调用存储库,它会执行两件事:
我想在第 1 步之后完成活动,但即使在活动完成后仍继续执行第 2 步(这当然也会清除viewModel
,这将取消 API 请求)。
我希望它的行为像这样,因为如果我只是等待两者都完成并且用户的互联网连接速度很慢,它可能会超时并使用户等待此活动。 相反,我觉得在本地完成任务(完成活动并让他在应用程序中做其他事情)并等待服务器的响应然后同步发生的事情(当然如果任务没有完全完成,当用户拥有更好的互联网连接时,我将不得不同步它,但这是题外话)。
目前我有这样的事情(它描述了超时的坏情况):
活动:
viewModel.addItemLiveData.observe(this) { success ->
if(success) //Toast well done
else //Something went wrong
finish()
}
button.setOnClickListener {
val item = ... //Collected from the UI
viewModel.addItem(item)
}
视图模型:
private val _addItemLiveData = MutableLiveData<Boolean>()
val addItemLiveData: LiveData<Boolean> = _addItemLiveData
fun addItem(item: Item) = viewModelScope.launch {
val id = repository.addItem(item)
_addItemLiveData.value = id > 0
}
存储库:
suspend fun addItem(item: Item) {
val id = roomDao.insert(item)
//This part needs to run after the viewModel's lifecycle
val res = apiService.insert(item) //Wrapped in a convenient class to indicate Success or Error
if(res is Resource.Success) {
roomDao.update(res.value)
}
}
(为简洁起见省略了一些代码)
我想也许我可以以某种方式执行GlobalScope.launch
,但我读到它不是使用它的最佳实践(而且我对 kotlin 仍然很陌生,所以我什至不完全确定如何去做)。
另外,也许我没有正确处理这个问题。 任何帮助表示赞赏。
您可以创建一个与您的应用程序生命周期相关联的协程范围。 如果您使用依赖注入,您应该将此范围注入您的 viewModel。 如果没有,您可以在自定义应用程序类中创建一个范围。
class MyCustomApplication: Application() {
val applicationScope = CoroutineScope(SupervisorJob())
}
class MyViewModel(private val app: MyCustomApplication) { // provide an instance of your custom application to view model
suspend fun addItem(item: Item) {
val id = roomDao.insert(item)
app.applicationScope.launch {
val res = apiService.insert(item) //Wrapped in a convenient class to indicate Success or Error
if(res is Resource.Success) {
roomDao.update(res.value)
}
}
}
}
你可以通过这个文章的更多细节。
您可以使用NonCancellable
上下文来创建一个在作业或范围被取消时不会被中断的挂起块:
suspend fun addItem(item: Item) {
val id = roomDao.insert(item)
//This part needs to run after the viewModel's lifecycle
withContext(NonCancellable) {
val res = apiService.insert(item) //Wrapped in a convenient class to indicate Success or Error
if(res is Resource.Success) {
roomDao.update(res.value)
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.