Kotlin Flow vs LiveData


10

Nell'ultimo I / O di Google, Jose Alcerreca e Yigit Boyar ci hanno detto che non dovremmo più utilizzare LiveData per recuperare i dati. Ora dovremmo usare le funzioni di sospensione per i recuperi one-shot e usare Kotlin's Flow per creare un flusso di dati. Concordo sul fatto che le coroutine sono ottime per il recupero di una sola ripresa o altre operazioni CRUD, come l'inserimento, ecc. Ma nei casi in cui ho bisogno di un flusso di dati, non capisco quali vantaggi mi offre Flow. Mi sembra che LiveData stia facendo lo stesso.

Esempio con flusso:

ViewModel

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

deposito

fun fetchItems() = itemDao.getItems()

Dao

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

Esempio con LiveData:

ViewModel

val items = repository.fetchItems()

deposito

fun fetchItems() = itemDao.getItems()

Dao

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

Vorrei anche vedere alcuni esempi di progetti che utilizzano coroutine e Flow per lavorare con Room o Retrofit. Ho trovato solo un esempio ToDo di Google in cui vengono utilizzate le coroutine per il recupero one-shot e quindi il recupero manuale dei dati al momento della modifica.

Risposte:


3

Flowè una specie di a reactive stream(come rxjava). Ci sono un sacco di operatori diversi, come .map, buffer()(comunque meno no. Dell'operatore rispetto al rxJava). Quindi, una delle principali differenze tra LiveDatae Flowè che puoi abbonarti alla mappa computation / transformationin qualche altro thread usando

 flowOn(Dispatcher....). 

Quindi, ad esempio: -

 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 )

Con LiveDatae map, quanto sopra non può essere realizzato direttamente!

Quindi si consiglia di mantenere il flusso a livello di repository e di rendere laivedata un ponte tra l'interfaccia utente e il repository!

La differenza principale è che flowha un sacco di operatori diversi che livedatanon hanno! Ma di nuovo, sta a te come vuoi costruire il tuo progetto!


3

Come suggerisce il nome, puoi pensare a Flow come a un flusso continuo di più valori calcolati in modo asincrono. La differenza principale tra LiveData e Flow, dal mio punto di vista, è che un flusso emette continuamente risultati mentre LiveData si aggiorna quando tutti i dati vengono recuperati e restituisce tutti i valori contemporaneamente. Nel tuo esempio stai recuperando singoli valori, che non è esattamente ciò per cui Flow è stato concepito secondo me.

Non ho un esempio di Room, ma supponiamo che si stia eseguendo il rendering di qualcosa che richiede tempo, ma si desidera visualizzare i risultati durante il rendering e il buffering dei risultati successivi.

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

Quindi nella tua funzione 'Riproduzione' puoi ad esempio visualizzare i risultati in cui stuffToPlay è un Elenco di oggetti da renderizzare, come:

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

Una caratteristica importante di Flow è che il suo codice builder (qui funzione di rendering) viene eseguito solo quando viene raccolto, quindi è un flusso freddo .

Puoi anche fare riferimento ai documenti su Asynchronous Flow

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.