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é que Google exemple ToDo 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.
Flow
est 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). Ainsi, l'une des principales différences entre LiveData
et Flow
est que vous pouvez souscrire la carte computation / transformation
Dans 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 LiveData
et map
, ce qui précède ne peut pas être atteint directement!
Il est donc recommandé de maintenir 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 que flow
a un tas d'opérateurs différents que livedata
n'a pas! Mais encore une fois, c'est à vous comment voulez-vous construire votre projet!
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 la raison pour laquelle Flow a été créé à 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 '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 constructeur (ici la fonction de rendu) n'est exécuté que lorsqu'il est collecté, d'où son flux a froid.
Vous pouvez également vous référer aux documents sur Asynchronous Flow