Котлин Флоу против LiveData

10

В прошлых операциях ввода-вывода Google Хосе Альсеррека и Йигит Бояр сказали нам, что мы больше не должны использовать LiveData для получения данных. Теперь мы должны использовать функции приостановки для однократных выборок и использовать поток Котлина для создания потока данных. Я согласен, что сопрограммы отлично подходят для выборочной загрузки или других операций CRUD, таких как вставка и т. Д. Но в тех случаях, когда мне нужен поток данных, я не понимаю, какие преимущества дает мне Flow. Мне кажется, что LiveData делает то же самое.

Пример с потоком:

ViewModel

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

вместилище

fun fetchItems() = itemDao.getItems()

Dao

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

Пример с LiveData:

ViewModel

val items = repository.fetchItems()

вместилище

fun fetchItems() = itemDao.getItems()

Dao

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

Я также хотел бы увидеть некоторые примеры проектов, использующих сопрограммы и Flow для работы с Room или Retrofit. Я нашел только образец задачи Google, в котором сопрограммы используются для выборочной выборки, а затем вручную обновляются данные при изменении.

Дмитрий Симаков
источник

Ответы:

3

Flowэто своего рода reactive stream(как rxjava). Есть множество различных операторов, таких как .map, buffer()(во всяком случае, меньше операторов по сравнению с rxJava). Итак, одно из основных различий между LiveDataи Flowзаключается в том, что вы можете подписать карту computation / transformationв другом потоке, используя

 flowOn(Dispatcher....). 

Так, например:

 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 )

С LiveDataи mapвышеописанное не может быть достигнуто напрямую!

Поэтому рекомендуется поддерживать поток на уровне репозитория и сделать livingata мостом между пользовательским интерфейсом и репозиторием!

Основное отличие состоит в том, что flowесть куча разных операторов, которых livedataнет! Но опять же, до вас, как вы хотите построить свой проект!

Santanu Sur
источник
3

Как следует из названия, вы можете думать о Flow как о непрерывном потоке нескольких асинхронно вычисляемых значений. Основное различие между LiveData и Flow, с моей точки зрения, состоит в том, что Flow непрерывно генерирует результаты, в то время как LiveData обновляется, когда все данные извлекаются, и возвращает все значения одновременно. В вашем примере вы выбираете отдельные значения, что, на мой взгляд, не совсем то, для чего был создан Flow.

У меня нет примера Room, но давайте представим, что вы рендерите что-то, что требует времени, но вы хотите отображать результаты при рендеринге и буферизации следующих результатов.

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

Затем в функции «Воспроизведение» вы можете, например, отобразить результаты, где stuffToPlay - это список объектов для рендеринга, например:

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

Важной характеристикой Flow является то, что его код компоновщика (здесь функция рендеринга) выполняется только тогда, когда он собран, и, следовательно, является холодным потоком.

Вы также можете обратиться к документации в Asynchronous Flow

nulldroid
источник