por qué cambia si se usa la función ShareIn o no
val sharedf = MutableSharedFlow<Int>() fun Flow<Int>.print() : Flow<Int> { return map { println("in print : $it") it } } fun Flow<String>.printS() : Flow<Int> { return map { println("in print : $it") it.toInt() } } fun Flow<Int>.toNext() : Flow<Int> { return merge( filterIsInstance<Int>().print(), filterIsInstance<String>().printS(), ) }cuando uso la función principal como esta
fun main() = runBlocking<Unit> { launch { sharedf.onSubscription{ println("subsCount : ${sharedf.subscriptionCount.value}") } .shareIn(GlobalScope, SharingStarted.Lazily) .toNext() .collect() } launch { for (i in 0..3){ delay(500) sharedf.emit(i) } } }número de subs: 1
pero si elimino ShareIn
número de subs: 2
por qué tengo que usar ShareIn incluso sharedf ya es MutableSharedFlow
Mirando toNext , puede ver que crea 2 flujos desde el flujo del receptor ( this ) usando dos veces filterIsInstance y fusionando esos 2 flujos. Por lo tanto, cuando recopila someFlow.toNext() , recopilará el doble del flujo de origen original someFlow .
Es por eso que, si no coloca shareIn en su método principal, verá 2 suscriptores en sharedf . toNext().collect() se suscribe dos veces al flujo compartido debido a la implementación de toNext() como acabamos de ver.
Ahora, si agrega shareIn() en el medio, crea otro flujo compartido independiente . Llamémoslo shared2 y extráigalo a una variable para que quede más claro:
val shared2 = sharedf.onSubscription { ... }.shareIn(GlobalScope, SharingStarted.Lazily) shared2.toNext().collect() En cierto modo, ese nuevo flujo compartido shared2 "protege" el flujo fuente sharedf de los recopiladores. Cuando muchos recopiladores recopilan shared2 , shared2 solo recopila una vez el flujo de origen sharedf .
Entonces, incluso si toNext() recopila shared2 dos veces, shared2 solo recopila sharedf una vez, por lo que solo ve 1 suscripción en sharedf en su registro.
por qué tengo que usar ShareIn incluso sharedf ya es MutableSharedFlow
¿Qué te hace pensar que tienes que hacer eso? Crear un flujo compartido a través de shareIn a partir de un flujo que ya es un flujo compartido es realmente inesperado.
Nota al margen: puede usar onEach en lugar de map en su función de print
La forma en que funciona shareIn en términos muy simples es que inicia una corrutina que se ejecuta indefinidamente y recopila el flujo de origen para volver a emitir esos valores. Por lo tanto, a diferencia de los operadores de map y merge que crean flujos fríos que solo se suscriben a la fuente cuando se recopilan, shareIn crea un flujo que inmediatamente comienza a recopilar desde el flujo de origen, por lo que se cuenta inmediatamente como un suscriptor del flujo de origen.
El toNext() descendente envuelve el segundo SharedFlow, no el primero. El primero no sabe acerca de los suscriptores descendentes. Solo emite al único SharedFlow desde la llamada shareIn , por lo que solo tiene un suscriptor.
Cuando elimina shareIn , su SharedFlow de nivel superior está emitiendo a los dos suscriptores que se crean en su llamada merge() () de toNext() , por lo que ve dos suscriptores. Tenga en cuenta que no verá ningún suscriptor hasta que se llame a collect , ya que esos son envoltorios fríos.