我想要一个按钮在导航到另一个片段之前执行 viewmodel 的方法,但似乎在更改屏幕之前它没有等待所有挂起功能完成:
View.class
nextButton.setOnClickListener {
val action = FragmentDirections.AToB()
lifecycleScope.launch {
getViewModel().doSomething()
findNavController().safeNavigate(action)
}
}
ViewModel.class
suspend fun doSomething() {
viewModelScope.launch { //tested with Context.IO and without Context
// long running suspend fun, or even delay(10000)
// screen is navigating before previous instruction finishes
}
}
使用
viewModelScope.launch
会启动单独的协程,可能会导致在正在进行的操作完成之前导航到新屏幕。推荐的方法是在开始导航之前使用 LiveData
观察操作的完成情况。
private val _operationComplete = MutableLiveData<Boolean>()
val operationComplete: LiveData<Boolean>
get() = _operationComplete
suspend fun doSomething() {
viewModelScope.launch {
// Long running suspend fun or delay(10000)
_operationComplete.value = true
}
}
在涉及确保及时完成的小型操作的场景中,可以考虑使用
join
,只要它能确保防止 ANR 问题。
suspend fun doSomething() {
val job = viewModelScope.launch {
// Long running suspend fun or delay(10000)
}
job.join() // Wait for the coroutine to complete
// Now navigate to the other fragment
}
您还可以创建自定义协程作用域并使用它来启动挂起函数。这样,您可以更明确地控制行为。
private val customScope = CoroutineScope(Dispatchers.Default)
suspend fun doSomething() {
customScope.launch {
// Long running suspend fun or delay(10000)
}.join()
}
根据您的情况,我建议采用第一种方法。快乐编码:)