运行 协程超过 viewModelScope 生命周期
Run coroutine past viewModelScope lifecycle
我需要确保即使 viewModel
被清除,挂起功能也会完成。
例如,我的应用程序中有一个按钮,当单击它时会调用 viewModel.addItem(item)
,该函数会调用存储库,它会做两件事:
- 将项目插入本地数据库
- 向 API 发送请求以插入项目(并等待响应以更新项目)。
我想在 第 1 步 之后完成 activity,但即使在 activity 完成后仍继续第 2 步(这也会清除 viewModel
当然,这将取消 API 请求)。
我希望它表现得像这样,因为如果我只是等待两者都完成 和 用户的互联网连接速度很慢,它可能会超时并使用户等等 activity。相反,我觉得在本地完成任务(完成 activity 并让他在应用程序中做其他事情)并等待服务器响应然后同步发生的事情(当然如果任务根本没有完成,我必须在用户拥有更好的互联网连接时同步它,但这是题外话)。
目前我有这样的东西(它描述了超时的糟糕情况):
Activity:
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。
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)
}
}
}
}
您可以阅读 this 文章了解更多详情。
您可以使用 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)
}
}
}
我需要确保即使 viewModel
被清除,挂起功能也会完成。
例如,我的应用程序中有一个按钮,当单击它时会调用 viewModel.addItem(item)
,该函数会调用存储库,它会做两件事:
- 将项目插入本地数据库
- 向 API 发送请求以插入项目(并等待响应以更新项目)。
我想在 第 1 步 之后完成 activity,但即使在 activity 完成后仍继续第 2 步(这也会清除 viewModel
当然,这将取消 API 请求)。
我希望它表现得像这样,因为如果我只是等待两者都完成 和 用户的互联网连接速度很慢,它可能会超时并使用户等等 activity。相反,我觉得在本地完成任务(完成 activity 并让他在应用程序中做其他事情)并等待服务器响应然后同步发生的事情(当然如果任务根本没有完成,我必须在用户拥有更好的互联网连接时同步它,但这是题外话)。
目前我有这样的东西(它描述了超时的糟糕情况):
Activity:
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。
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)
}
}
}
}
您可以阅读 this 文章了解更多详情。
您可以使用 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)
}
}
}