¿Cómo puedo obtener el valor de un Flujo fuera de una corrutina de manera similar a LiveData?
// 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).valueContexto
Estoy evitando LiveData en la capa de repositorio a favor de Flow . Sin embargo, necesito establecer, observar y recopilar el valor para el consumo inmediato. El último es útil para fines de autenticación en un Interceptor OkHttp3.
Bueno... lo que estás buscando no es realmente para lo que es Flow . Flow es solo una corriente. No es un titular de valor, por lo que no hay nada que recuperar.
Entonces, hay dos vías principales para bajar, dependiendo de lo que necesite su interceptor.
Quizás su interceptor pueda vivir sin los datos del repositorio. IOW, usará los datos si existen, pero de lo contrario, el interceptor puede continuar. En ese caso, puede hacer que su repositorio emita un flujo, pero también puede mantener un caché de "valor actual" que su interceptor puede usar. Eso podría ser a través de:
BroadcastChannelLiveDataval Sin embargo, si su interceptor necesita los datos, entonces ninguno de ellos funcionará directamente, porque todos darán como resultado que el interceptor se vuelva null si los datos aún no están listos. Lo que necesitaría es una llamada que pueda bloquear, pero que quizás evalúe rápidamente si los datos están listos a través de algún tipo de caché. Los detalles de eso variarán mucho según la implementación del repositorio y lo que está suministrando el Flow en primer lugar.
Puedes hacerlo
val flowValue: SomeType runBlocking(Dispatchers.IO) { flowValue = myFlow.first() }Sí, no es exactamente para lo que se hizo Flow.
Pero no siempre es posible hacer que todo sea asincrónico y, de hecho, es posible que ni siquiera siempre sea posible 'simplemente hacer un método sincrónico'. Por ejemplo, las versiones actuales de Datastore (que se supone que reemplazan las preferencias compartidas en Android) solo exponen Flow y nada más. Lo que significa que muy fácilmente entrará en tal situación, dado que ninguno de los métodos de Ciclo de vida de Actividades o Fragmentos son corrutinas.
Si puede evitarlo, siempre debe llamar a las corrutinas desde las funciones de suspensión y evitar hacer llamadas de runBlocking . Muchas veces funciona así. Pero no es una forma segura que funcione todo el tiempo. Puede introducir interbloqueos con runBlocking .
Podrías usar algo como esto:
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 }Puede usar MutableStateFlow y MutableSharedFlow para emitir los datos de coroutine y recibir los datos dentro de Activity/Fragment . MutableStateFlow se puede utilizar para la gestión de estado. Requiere un valor predeterminado cuando se inicializa. Mientras que MutableSharedFlow no necesita ningún valor predeterminado.
Pero, si no desea recibir un flujo de datos, (es decir) su llamada a la API envía datos solo una vez, puede usar la función de suspensión dentro del alcance de la rutina y la función realizará la tarea y devolverá el resultado como una llamada de función síncrona.