Kotlin Flow vs LiveData

10

Dans les dernières E / S de Google, Jose Alcerreca et Yigit Boyar nous ont dit que nous ne devrions plus utiliser LiveData pour récupérer des données. Maintenant, nous devons utiliser les fonctions de suspension pour les récupérations ponctuelles et utiliser le flux de Kotlin pour créer un flux de données. Je conviens que les coroutines sont idéales pour l'extraction en une seule opération ou d'autres opérations CRUD, telles que l'insertion, etc. Mais dans les cas où j'ai besoin d'un flux de données, je ne comprends pas quels avantages Flow me donne. Il me semble que LiveData fait de même.

Exemple avec Flow:

ViewModel

val items = repository.fetchItems().asLiveData()

Dépôt

fun fetchItems() = itemDao.getItems()

Dao

@Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>

Exemple avec LiveData:

ViewModel

val items = repository.fetchItems()

Dépôt

fun fetchItems() = itemDao.getItems()

Dao

@Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>

J'aimerais également voir quelques exemples de projets utilisant des coroutines et Flow pour travailler avec la salle ou le retrofit. Je n'ai trouvé qu'un échantillon ToDo de Google où les coroutines sont utilisées pour la récupération en une seule fois, puis récupérer manuellement les données lors de la modification.

Dmitry Simakov
la source

Réponses:

3

Flowest une sorte de reactive stream(comme rxjava). Il y a un tas d'opérateurs différents comme .map, buffer()(de toute façon moins non. D'opérateur par rapport à rxJava). Donc, l'une des principales différences entre LiveDataet Flowest que vous pouvez souscrire la carte computation / transformationdans un autre thread en utilisant

 flowOn(Dispatcher....). 

Ainsi, par exemple: -

 flowOf("A","B","C").map { compute(it) }.flowOn(Dispatchers.IO).collect {...} // U can change the execution thread of the computation ( by default its in the same dispatcher as collect )

Avec LiveDataet map, ce qui précède ne peut pas être atteint directement!

Il est donc recommandé de garder le flux au niveau du référentiel et de faire des données vivantes un pont entre l'interface utilisateur et le référentiel!

La principale différence est qu'il flowa un tas d'opérateurs différents qui livedatan'en ont pas! Mais encore une fois, c'est à vous comment voulez-vous construire votre projet!

Santanu Sur
la source
3

Comme son nom l'indique, vous pouvez considérer Flow comme un flux continu de plusieurs valeurs calculées de manière asynchrone. La principale différence entre LiveData et Flow, de mon point de vue, est qu'un Flow émet en continu des résultats tandis que LiveData se met à jour lorsque toutes les données sont récupérées et renvoie toutes les valeurs à la fois. Dans votre exemple, vous récupérez des valeurs uniques, ce qui n'est pas exactement ce pour quoi Flow a été conçu à mon avis.

Je n'ai pas d'exemple de salle, mais disons que vous effectuez un rendu qui prend du temps, mais vous voulez afficher les résultats tout en rendant et en tamponnant les résultats suivants.

private fun render(stuffToPlay: List<Any>): Flow<Sample> = flow {
     val sample = Sample()
     // computationally intensive operation on stuffToPlay
     Thread.sleep(2000)
     emit(sample)
}

Ensuite, dans votre fonction de lecture, vous pouvez par exemple afficher les résultats où stuffToPlay est une liste d'objets à restituer, comme:

playbackJob = GlobalScope.launch(Dispatchers.Default) {

    render(stuffToPlay)
        .buffer(1000)   // tells the Flow how many values should be calculated in advance

        .onCompletion {
            // gets called when all stuff got played
        }
        .collect{sample ->
           // collect the next value in the buffered queue
           // e.g. display sample
        }
}

Une caractéristique importante de Flow est que son code de générateur (ici la fonction de rendu) n'est exécuté que lorsqu'il est collecté, d'où son flux froid .

Vous pouvez également consulter les documents sur Asynchronous Flow

nulldroid
la source