如何获取协程外Flow的值?
How to get the value of a Flow outside a coroutine?
如何像 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
.
中的身份验证目的很有用
嗯...您要找的并不是 Flow
真正要找的。 Flow
只是一个流。它不是一个价值持有者,所以你没有任何东西可以取回。
因此,根据您的拦截器的需要,有两种主要途径。
也许您的拦截器可以在没有来自存储库的数据的情况下生存。 IOW,如果数据存在,您将使用它,否则拦截器可以继续。在这种情况下,您可以让您的存储库发出流,但也可以维护您的拦截器可以使用的 "current value" 缓存。这可能是通过:
BroadcastChannel
LiveData
- 存储库中的一个简单 属性,您可以在内部更新并公开为
val
如果您的拦截器需要数据,那么 none 将直接工作,因为如果数据尚未准备好,它们都会导致拦截器获得 null
。您需要的是 can 阻塞的调用,但如果数据已通过某种形式的缓存准备就绪,则可能会快速评估。根据存储库的实现以及首先提供 Flow
的内容,其细节会有很大差异。
你可以做到这一点
val flowValue: SomeType
runBlocking(Dispatchers.IO) {
flowValue = myFlow.first()
}
是的,它并不完全是 Flow 的用途。
但并不总是可以让所有事情都异步,就此而言,甚至 'just make a synchronous method' 也不总是可能的。例如,当前的 Datastore 版本(应该取代 Android 上的共享首选项)只公开 Flow 而没有其他内容。这意味着您很容易陷入这种情况,因为 Activity 或 Fragment 的生命周期方法中有 none 是协程。
如果可以的话,您应该始终从挂起函数调用协程并避免进行 runBlocking
调用。很多时候它是这样工作的。但这并不是一种万无一失的方法。您可以使用 runBlocking
.
引入死锁
你可以使用这样的东西:
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
}
您可以使用 MutableStateFlow and MutableSharedFlow 从协程发出数据并在 Activity/Fragment
中接收数据。 MutableStateFlow
可用于状态管理。初始化时需要默认值。而 MutableSharedFlow
不需要任何默认值。
但是,如果您不想接收数据流,(即)您的 API 调用只发送一次数据,您可以在协程范围内使用挂起函数,该函数将执行任务并且return 类似同步函数调用的结果。
如何像 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
.
嗯...您要找的并不是 Flow
真正要找的。 Flow
只是一个流。它不是一个价值持有者,所以你没有任何东西可以取回。
因此,根据您的拦截器的需要,有两种主要途径。
也许您的拦截器可以在没有来自存储库的数据的情况下生存。 IOW,如果数据存在,您将使用它,否则拦截器可以继续。在这种情况下,您可以让您的存储库发出流,但也可以维护您的拦截器可以使用的 "current value" 缓存。这可能是通过:
BroadcastChannel
LiveData
- 存储库中的一个简单 属性,您可以在内部更新并公开为
val
如果您的拦截器需要数据,那么 none 将直接工作,因为如果数据尚未准备好,它们都会导致拦截器获得 null
。您需要的是 can 阻塞的调用,但如果数据已通过某种形式的缓存准备就绪,则可能会快速评估。根据存储库的实现以及首先提供 Flow
的内容,其细节会有很大差异。
你可以做到这一点
val flowValue: SomeType
runBlocking(Dispatchers.IO) {
flowValue = myFlow.first()
}
是的,它并不完全是 Flow 的用途。
但并不总是可以让所有事情都异步,就此而言,甚至 'just make a synchronous method' 也不总是可能的。例如,当前的 Datastore 版本(应该取代 Android 上的共享首选项)只公开 Flow 而没有其他内容。这意味着您很容易陷入这种情况,因为 Activity 或 Fragment 的生命周期方法中有 none 是协程。
如果可以的话,您应该始终从挂起函数调用协程并避免进行 runBlocking
调用。很多时候它是这样工作的。但这并不是一种万无一失的方法。您可以使用 runBlocking
.
你可以使用这样的东西:
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
}
您可以使用 MutableStateFlow and MutableSharedFlow 从协程发出数据并在 Activity/Fragment
中接收数据。 MutableStateFlow
可用于状态管理。初始化时需要默认值。而 MutableSharedFlow
不需要任何默认值。
但是,如果您不想接收数据流,(即)您的 API 调用只发送一次数据,您可以在协程范围内使用挂起函数,该函数将执行任务并且return 类似同步函数调用的结果。