【问题标题】:How to pause/stop collecting/emitting data in a Flow while app minimised?如何在应用程序最小化时暂停/停止收集/发送流中的数据?
【发布时间】:2021-05-30 15:46:41
【问题描述】:

我有一个循环返回 Flow 的 UseCase 和远程存储库,我在 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
            }
        }
    }
}

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

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

【问题讨论】:

  • 如果您希望根据 UI 的生命周期来更改某些内容,为什么不将其绑定到您的 UI?看起来你正在与你需要的东西作斗争。
  • 在视图中收集或观察远程数据源是一种反模式,因此我们必须在 ViewModel 中这样做。但我们那里没有 ViewLifeCycle 所以我认为这是我的问题。我尝试了 MediatorLiveData 和 Stateflow,但它们没有帮助我。
  • 我想看看你引用的是什么来源,因为生命周期感知正是 UI 中收集的用途以及 Guide to app architecture 所讨论的内容。来自 result 的数据如何输入到您的 UI 中?听起来您实际上正在寻找的是 map 来将您的定期更新转换为您的 UI 需要。
  • useCase.updatePeriodically()函数的实现是什么?
  • @YuriiKot 其实没关系,只是回流

标签: android viewmodel android-lifecycle kotlin-coroutines


【解决方案1】:

即使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

【讨论】:

    【解决方案2】:

    我会尝试使用 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()
    }
    
    
    
    

    【讨论】:

    • 问题正是不想在视图中收集流量。
    猜你喜欢
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多