如何获得协程外部流程的价值?

时间:2020-04-13 20:56:57

标签: android kotlin kotlin-flow

如何像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 个答案:

答案 0 :(得分:2)

好吧...您要找的东西并不是Flow的真正目的。 Flow只是一个流。它不是值持有者,因此没有任何可检索的内容。

因此,根据拦截器的需求,有两种主要的解决方法。

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

  • BroadcastChannel
  • LiveData
  • 存储库中的一个简单属性,您可以在内部对其进行更新,并显示为val

但是,如果您的拦截器需要数据,那么这些都不会直接起作用,因为如果数据还没有准备好,它们都会导致拦截器获得null。您需要的是一个可以阻止的调用,但是可能会通过某种形式的缓存快速评估数据是否准备就绪。具体细节将取决于存储库的实现以及首先提供Flow的内容。

答案 1 :(得分:1)

您应该查看 StateFlow,在那里您可以访问该值。

https://developer.android.com/kotlin/flow/stateflow-and-sharedflow

答案 2 :(得分:0)

您可以这样做

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

是的,它并不是为Flow制造的。

但是并非总是可以使所有内容都异步,因此,甚至不可能总是仅“使之成为同步方法”。例如,当前的数据存储版本(应该替换Android上的共享首选项)仅公开Flow,而没有其他功能。这意味着,鉴于“活动”或“片段”的生命周期方法都不是协程,您将很容易陷入这种情况。

如果可以帮助您,则应始终从协程调用协程,并避免进行runBlocking调用。很多时候它是这样工作的。但这并不是始终有效的保证方式。您可以使用runBlocking引入死锁。

答案 3 :(得分: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
    }