如何在应用程序最小化时暂停/停止收集/发送流中的数据?

Far*_*ABZ 5 android viewmodel android-lifecycle kotlin-coroutines

我有一个 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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是当应用程序处于后台(最小化)时流程继续工作。那么我可以在应用程序在后台时暂停它并在应用程序返回前台时恢复它吗?

而且我也不想观察我视图中的数据(片段或活动)。

Kar*_*rma 6

即使 viewModelScope 被取消,流也会继续收集,因为它不配合取消。

要使流程可取消,您可以执行以下操作之一:

  1. 在collect lambda 中,调用currentCoroutineContext().ensureActive()以确保收集流的上下文仍然处于活动状态。然而,如果协程作用域已经被取消(您的案例的 viewModel 作用域),这将抛出 CancellableException,您需要捕获该异常。

  2. 您可以cancellable()按如下方式使用运算符:

    myFlow.cancellable().collect { //do stuff here.. } 您可以cancel()随时致电取消流程。

有关取消流程的官方文档,请参阅:

https://kotlinlang.org/docs/flow.html#flow-cancellation-checks


Nag*_*obi 3

我会尝试使用stateIn运算符以及我当前在视图中使用流的方式。

就像是:

val state = useCase.updatePeriodically().map { ... }
    .stateIn(viewModelScope, SharingStarted.WhileSubscribed, initialValue)
Run Code Online (Sandbox Code Playgroud)

并从视图中使用它,如下所示:

viewModel.flowWithLifecycle(this, Lifecycle.State.STARTED)
            .onEach {
                
            }
            .launchIn(lifecycleScope) 
Run Code Online (Sandbox Code Playgroud)

有关如何从 UI 收集流量的其他潜在方法:https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda

编辑:

如果您不想从视图中使用它,您仍然需要向虚拟机发出信号,表明您的视图当前位于后台。就像是:

private var job: Job? = null

fun start(){
    job = viewModelScope.launch {
        state.collect { ... }
    }
}

fun stop(){
    job?.cancel()
}



Run Code Online (Sandbox Code Playgroud)