繁体   English   中英

在 viewModelScope 生命周期后运行协程

[英]Run coroutine past viewModelScope lifecycle

我需要确保即使清除了viewModel也会完成挂起功能。 例如,我的应用程序中有一个按钮,单击该按钮时会调用viewModel.addItem(item) ,然后该函数会调用存储库,它会执行两件事:

  1. 将项目插入本地数据库
  2. 向 API 发送请求以插入项目(并等待响应更新项目)。

我想在第 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM