我有一个 UseCase 和远程存储库,它们在循环中返回 Flow,我在 ViewModel 中收集 UseCase 的结果,如下所示:
viewModelScope.launch {
useCase.updatePeriodically().collect { result ->
when (result.status) {
Result.Status.ERROR -> {
errorModel.value = result.errorModel
}
Result.Status.SUCCESS -> {
items.value = result.data
}
Result.Status.LOADING -> {
loading.value = true
}
}
}
}
问题是当应用程序在后台(最小化)流程继续工作时。那么我可以在应用程序处于后台时暂停它,并在应用程序返回前台时恢复它吗?
而且我不想观察我视图中的数据(片段或活动)。
我会尝试使用 stateIn 运算符以及我当前在视图中使用流的方式。
类似的东西:
val state = useCase.updatePeriodically().map { ... }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed, initialValue)
并从视图中使用它,例如:
viewModel.flowWithLifecycle(this, Lifecycle.State.STARTED)
.onEach {
}
.launchIn(lifecycleScope)
有关如何从 UI 收集流的其他潜在方法:https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda
编辑:
如果您不想从视图中使用它,您仍然必须向 VM 发出信号,表明您的视图当前处于后台。 像这样的东西:
private var job: Job? = null
fun start(){
job = viewModelScope.launch {
state.collect { ... }
}
}
fun stop(){
job?.cancel()
}
即使取消了viewModelScope,流程也会继续收集,因为它不配合取消。
要使流程可取消,您可以执行以下操作之一:
在收集 lambda 中,调用 currentCoroutineContext().ensureActive()
以确保收集流的上下文仍然处于活动状态。但是,如果协程范围已经被取消(您的案例的 viewModel 范围),这将抛出一个 CancellableException,您需要捕获它。
您可以使用 cancellable()
运算符,如下所示:
myFlow.cancellable().collect { //do stuff here.. }
你可以随时调用 cancel()
取消流程。
关于取消流的官方文档见:
https://kotlinlang.org/docs/flow.html#flow-cancellation-checks
我相信你想要这样的东西
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
state.collect {
}
}
}
这里有一篇关于 repeatOnLifecyle 的优秀文章:https://medium.com/androiddevelopers/repeatonlifecycle-api-design-story-8670d1a7d333