Kotlin Flow gegen LiveData

10

In der letzten Google-E / A haben Jose Alcerreca und Yigit Boyar uns mitgeteilt, dass wir LiveData nicht mehr zum Abrufen von Daten verwenden sollten. Jetzt sollten wir Suspend-Funktionen für One-Shot-Abrufe verwenden und Kotlins Flow verwenden, um einen Datenstrom zu erstellen. Ich bin damit einverstanden, dass Coroutinen sich hervorragend zum One-Shot-Abrufen oder für andere CRUD-Vorgänge wie das Einfügen usw. eignen. In Fällen, in denen ich einen Datenstrom benötige, verstehe ich jedoch nicht, welche Vorteile Flow mir bietet. Es scheint mir, dass LiveData dasselbe tut.

Beispiel mit Flow:

ViewModel

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

Repository

fun fetchItems() = itemDao.getItems()

Dao

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

Beispiel mit LiveData:

ViewModel

val items = repository.fetchItems()

Repository

fun fetchItems() = itemDao.getItems()

Dao

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

Ich würde auch gerne einige Beispiele für Projekte sehen, bei denen Coroutinen und Flow für die Arbeit mit dem Raum oder der Nachrüstung verwendet werden. Ich habe nur ein ToDo-Beispiel von Google gefunden, in dem Coroutinen zum einmaligen Abrufen und anschließenden manuellen erneuten Abrufen von Daten beim Ändern verwendet werden.

Dmitry Simakov
quelle

Antworten:

3

Flowist eine Art a reactive stream(wie rxjava). Es gibt eine Reihe von verschiedenen Operatoren wie .map, buffer()(ohnehin nicht weniger. Der Betreiber im Vergleich zu rxJava). Einer der Hauptunterschiede zwischen LiveDataund Flowbesteht darin, dass Sie die Karte computation / transformationin einem anderen Thread mit abonnieren können

 flowOn(Dispatcher....). 

Also zum Beispiel: -

 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 )

Mit LiveDataund mapkann das oben genannte nicht direkt erreicht werden!

Es wird daher empfohlen, den Datenfluss auf Repository-Ebene beizubehalten und die Livedata zu einer Brücke zwischen der Benutzeroberfläche und dem Repository zu machen!

Der Hauptunterschied besteht darin, dass flowes eine Reihe verschiedener Operatoren gibt, die livedataes nicht gibt! Aber auch hier liegt es an dir, wie du dein Projekt konstruieren willst!

Santanu Sur
quelle
3

Wie der Name schon sagt, können Sie sich Flow als einen kontinuierlichen Fluss mehrerer asynchron berechneter Werte vorstellen. Der Hauptunterschied zwischen LiveData und Flow besteht aus meiner Sicht darin, dass ein Flow kontinuierlich Ergebnisse ausgibt, während LiveData aktualisiert wird, wenn alle Daten abgerufen werden, und alle Werte auf einmal zurückgibt. In Ihrem Beispiel rufen Sie einzelne Werte ab, wofür Flow meiner Meinung nach nicht genau gemacht wurde.

Ich habe kein Room-Beispiel, aber nehmen wir an, Sie rendern etwas, das Zeit braucht, aber Sie möchten Ergebnisse anzeigen, während Sie die nächsten Ergebnisse rendern und puffern.

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

Dann können Sie in Ihrer 'Wiedergabe'-Funktion beispielsweise die Ergebnisse anzeigen, bei denen stuffToPlay eine Liste der zu rendernden Objekte ist, wie z.

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
        }
}

Ein wichtiges Merkmal von Flow ist, dass sein Builder-Code (hier Renderfunktion) nur ausgeführt wird, wenn er gesammelt wird, daher ist es ein kalter Stream.

Sie können auch auf die Dokumente unter verweisen Asynchronous Flow

Nulldroid
quelle