Kotlin Flow vs LiveData

10

W ostatnim We / Wy Google Jose Alcerreca i Yigit Boyar powiedzieli nam, że nie powinniśmy już używać LiveData do pobierania danych. Teraz powinniśmy używać funkcji zawieszenia do pobierania jednorazowego i użyć przepływu Kotlina, aby utworzyć strumień danych. Zgadzam się, że coroutines świetnie nadają się do jednorazowego pobierania lub innych operacji CRUD, takich jak wstawianie itp. Ale w przypadkach, gdy potrzebuję strumienia danych, nie rozumiem, jakie korzyści daje mi Flow. Wydaje mi się, że LiveData robi to samo.

Przykład z przepływem:

ViewModel

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

Magazyn

fun fetchItems() = itemDao.getItems()

Dao

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

Przykład z LiveData:

ViewModel

val items = repository.fetchItems()

Magazyn

fun fetchItems() = itemDao.getItems()

Dao

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

Chciałbym również zobaczyć przykłady projektów wykorzystujących coroutines i Flow do pracy z Roomem lub Modernizacją. Znalazłem tylko próbkę Google do zrobienia ToDo, w której coroutines są używane do jednorazowego pobierania, a następnie ręcznego pobierania danych po zmianie.

Dmitrij Simakov
źródło

Odpowiedzi:

3

Flowjest swego rodzaju reactive stream(jak rxjava). Istnieje kilka różnych operatorów jak .map, buffer()(w każdym razie nie mniej. Operatora w porównaniu do rxJava). Jedną z głównych różnic między LiveDatai Flowjest to, że możesz subskrybować mapę computation / transformationw innym wątku za pomocą

 flowOn(Dispatcher....). 

Na przykład:

 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 )

Z LiveDatai mappowyższe nie można osiągnąć bezpośrednio!

Zaleca się więc utrzymanie przepływu na poziomie repozytorium i uczynienie z liveata pomostu między interfejsem użytkownika a repozytorium!

Główną różnicą jest to, że flowma wiele różnych operatorów, którzy livedatanie mają! Ale znowu, to zależy od ciebie, jak chcesz skonstruować swój projekt!

Santanu Sur
źródło
3

Jak sama nazwa wskazuje, możesz myśleć o Flow jak o ciągłym przepływie wielu asynchronicznie obliczonych wartości. Z mojego punktu widzenia główna różnica między LiveData i Flow polega na tym, że Flow ciągle wysyła wyniki, a LiveData aktualizuje się po pobraniu wszystkich danych i zwraca wszystkie wartości naraz. W twoim przykładzie pobierasz pojedyncze wartości, co moim zdaniem nie jest dokładnie tym, do czego został stworzony Flow.

Nie mam przykładu pokoju, ale powiedzmy, że renderujesz coś, co wymaga czasu, ale chcesz wyświetlać wyniki podczas renderowania i buforowania następnych wyników.

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

Następnie w funkcji „Odtwarzanie” możesz na przykład wyświetlić wyniki, w których stuffToPlay jest listą obiektów do renderowania, takich jak:

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

Ważną cechą Flow jest to, że jego kod konstruktora (tutaj funkcja renderowania) jest wykonywany tylko wtedy, gdy zostanie zebrany, stąd jego zimny strumień.

Możesz także odnieść się do dokumentów w Asynchronous Flow

nulldroid
źródło