13

与 LiveData 类似,如何在协程之外获取 Flow 的值?

// Suspend function 'first' should be called only from a coroutine or another suspend function
flowOf(1).first()
// value is null
flowOf(1).asLiveData().value
// works
MutableLiveData(1).value

语境

我避免LiveData在存储库层中支持Flow. 然而,我需要设置、观察和收集立即消费的价值。后者可用于 OkHttp3 中的身份验证目的Interceptor

4

4 回答 4

17

你可以这样做

val flowValue: SomeType
runBlocking(Dispatchers.IO) {
    flowValue = myFlow.first()
}

是的,它不完全是 Flow 的用途。

但它并不总是可以使一切都异步,就此而言,甚至可能并不总是可以“只制作一个同步方法”。例如,当前的 Datastore 版本(应该替换 Android 上的共享首选项)只公开 Flow 而没有其他任何内容。这意味着您将很容易陷入这种情况,因为活动或片段的生命周期方法都不是协程。

如果您能提供帮助,您应该始终从挂起函数调用协程并避免runBlocking调用。很多时候它是这样工作的。但这并不是始终有效的万无一失的方式。您可以使用runBlocking.

于 2020-10-17T21:48:18.153 回答
7

嗯......你正在寻找的并不是真正Flow的目的。Flow只是一个流。它不是价值持有者,因此您无法检索任何内容。

因此,根据拦截器的需求,有两种主要途径可以下降。

也许您的拦截器可以在没有来自存储库的数据的情况下生存。IOW,如果数据存在,您将使用该数据,否则拦截器可以继续。在这种情况下,您可以让您的存储库发出一个流,但也可以维护您的拦截器可以使用的“当前值”缓存。这可以通过:

  • BroadcastChannel
  • LiveData
  • 存储库中的一个简单属性,您可以在内部更新并公开为val

但是,如果您的拦截器需要数据,那么这些都不会直接工作,因为null如果数据尚未准备好,它们都会导致拦截器获取。您需要的是一个可以阻塞的调用,但如果数据通过某种形式的缓存准备好,可能会快速评估。根据存储库的实现以及首先提供的内容,其细节会有很大差异Flow

于 2020-04-13T22:08:44.903 回答
2

您可以使用MutableStateFlowMutableSharedFlow从协程发出数据并接收内部数据Activity/FragmentMutableStateFlow可用于状态管理。初始化时需要默认值。而不MutableSharedFlow需要任何默认值。

但是,如果您不想接收数据流,(即)您的 API 调用只发送一次数据,您可以在协程范围内使用挂起函数,该函数将执行任务并像同步函数调用一样返回结果。

于 2021-09-21T04:41:00.467 回答
0

你可以使用这样的东西:

    fun <T> SharedFlow<T>.getValueBlockedOrNull(): T? {
        var value: T?
        runBlocking(Dispatchers.Default) {
            value = when (this@getValueBlockedOrNull.replayCache.isEmpty()) {
                true -> null
                else -> this@getValueBlockedOrNull.firstOrNull()
            }
        }
        return value
    }
于 2021-07-18T08:58:34.013 回答