web-dev-qa-db-fra.com

Comment envoyer des éléments à un Kotlin.Flow (comme un sujet de comportement)

Je voulais savoir comment envoyer/émettre des éléments vers un Kotlin.Flow, donc mon cas d'utilisation est:

Dans le consommateur/ViewModel/Presenter, je peux souscrire avec la fonction collect:

fun observe() {
 coroutineScope.launch {
    // 1. Send event
    reopsitory.observe().collect {
      println(it)
    }
  }
}

Mais le problème est du côté Repository, avec RxJava nous pourrions utiliser un Behaviorsubject l'exposer comme un Observable/Flowable et émettre de nouveaux éléments comme celui-ci:

behaviourSubject.onNext(true)

Mais chaque fois que je crée un nouveau flux:

flow {

}

Je ne peux que collecter . Comment envoyer des valeurs à un flux?

10
Joaquim Ley

Si vous voulez obtenir la valeur dernier sur l'abonnement/la collection, vous devez utiliser un ConflatedBroadcastChannel :

private val channel = ConflatedBroadcastChannel<Boolean>()

Cela répliquera BehaviourSubject, pour exposer le canal en tant que flux:

// Repository
fun observe() {
  return channel.asFlow()
}

Maintenant, pour envoyer un événement/une valeur à ce simple envoi Flow exposé à ce canal.

// Repository
fun someLogicalOp() {
  channel.send(false) // This gets sent to the ViewModel/Presenter and printed.
}

Console:

false

Si vous souhaitez recevoir uniquement des valeurs après que vous avez commencé à collecter, vous devez utiliser un BroadcastChannel à la place.

Pour être clair:

Se comporte comme un Rx PublishedSubject

private val channel = BroadcastChannel<Boolean>(1)

fun broadcastChannelTest() {
  // 1. Send event
  channel.send(true)

  // 2. Start collecting
  channel
    .asFlow()
    .collect {
      println(it)
    }

  // 3. Send another event
  channel.send(false)
}

false

Seulementfalse est imprimé lors de l'envoi du premier événement avant collect { }.


Se comporte comme un Rx BehaviourSubject

private val confChannel = ConflatedBroadcastChannel<Boolean>()

fun conflatedBroadcastChannelTest() {
  // 1. Send event
  confChannel.send(true)

  // 2. Start collecting
  confChannel
    .asFlow()
    .collect {
      println(it)
    }

  // 3. Send another event
  confChannel.send(false)
}

vrai

false

Les deux événements sont imprimés, vous obtenez toujours la dernière valeur (si présente).

Je souhaite également mentionner le développement de l'équipe de Kotlin sur DataFlow (nom en attente):

Ce qui semble mieux adapté à ce cas d'utilisation (car ce sera un flux froid ).

16
Joaquim Ley