如何立即启动 lifecycle.whenResumed 协程,以便在返回之前开始流收集?

How to launch lifecycle.whenResumed coroutine immediately so flow-collection starts before returning?

我在 whenResumed 中收听一个流程,因此仅在应用程序恢复时收集事件。但是,我想确保在 运行 可能发送必须收集的事件的代码之前我已经启动了监听器。

init {
    lifecycleScope.launchWhenResumed {
        stateUpdates.collect { onUpdate(it) }
    }
    // Now do stuff that might trigger event, which I want to collect above.
    // This does not have to be in init {}, an initialize() is fine
    doMyThing()
}

我知道我可以将 sharedFlow 与缓存一起使用,但对于我的用例,缓存可能有问题。

--

我知道我可以执行以下操作,其中第 1 行立即执行,但这里再次调度第 2 行,因此稍后执行:

CoroutineScope(Dispatchers.Main).launch(start = CoroutineStart.UNDISPATCHED) {
    // 1
    lifecycle.whenResumed {
        // 2
    }
}

==== 更新 3. 2022 年 3 月

感谢 IR42 提供有关选项的有用信息。我实际上是在安排许多不同类型的收集器,然后做我的事。

init {
    lifecycleScope.launchWhenResumed {
        launch { stateUpdates1.collect { onUpdate1(it) } }
        launch { stateUpdates2.collect { onUpdate2(it) } }
        launch { stateUpdates3.collect { onUpdate3(it) } }
        launch { stateUpdates4.collect { onUpdate4(it) } }
        launch { stateUpdates5.collect { onUpdate5(it) } }
    }
    // Now do stuff that might trigger event, which I want to collect above.
    // This does not have to be in init {}, an initialize() is fine
    doMyThing()
}   

我想要一个很好的惯用方法来做到这一点。我不知道如何使用 onSubscription() 执行此操作,但我很感谢您的输入,因为它对我来说是新的。

我想我找到了解决办法。它需要在协程内部产生,所以其他所有调度在同一个 Dispatcher 上的协程(例如主线程)都有机会 运行.

lifecycleScope.launchWhenResumed {
    launch { stateUpdates1.collect { onUpdate1(it) } }
    launch { stateUpdates2.collect { onUpdate2(it) } }
}
// do other stuff if needed here, or join the two coroutines
lifecycleScope.launchWhenResumed {
    yield()
    // Do my thing, that might result in state-update
    doMyThing()
}

如果 yield() + doMyThing() 在同一个协程中,上面的方法同样有效。

Kotlin Coroutine Yield 还有这个问题

请注意,我之前有一个错误的答案涉及 运行Blocking { }。 RunBlocking 阻塞了我的 UI-thread 这是糟糕的设计,即使代码立即执行也是如此。它也不会在 运行Blocking 内部执行其他预定协程,这不是我所期望的。我从答案中删除了它,因为它不应该在生产代码中使用。另见

而不是这样做:

runBlocking {
    lifecycleScope.launchWhenResumed {
        stateUpdates.collect { onUpdate(it) }
    }
    yield()
}

这样做,它不那么脆弱:

lifecycleScope.launchWhenResumed {
    yield()
    stateUpdates.collect { onUpdate(it) }
}

不过,它仍然有点脆弱,因为它依赖于提交协程的顺序。

您可以使用onSubscription

lifecycleScope.launchWhenResumed {
    stateUpdates
        .onSubscription { 
            // Do my thing, that might result in state-update 
        }
        .collect { onUpdate(it) }
}