Kotlin Flow против LiveData
Во время последнего ввода-вывода Google Хосе Альсеррека и Йигит Бояр сказали нам, что мы больше не должны использовать LiveData для получения данных. Теперь мы должны использовать функции приостановки для одноразовой выборки и использовать поток Kotlin для создания потока данных. Я согласен с тем, что сопрограммы отлично подходят для одноразовой выборки или других операций CRUD, таких как вставка и т. Д. Но в случаях, когда мне нужен поток данных, я не понимаю, какие преимущества дает мне Flow. Мне кажется, что LiveData делает то же самое.
Пример с Flow:
ViewModel
val items = repository.fetchItems().asLiveData()
Репозиторий
fun fetchItems() = itemDao.getItems()
Дао
@Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>
Пример с LiveData:
ViewModel
val items = repository.fetchItems()
Репозиторий
fun fetchItems() = itemDao.getItems()
Дао
@Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>
Я также хотел бы увидеть несколько примеров проектов, использующих сопрограммы и Flow для работы с Room или Retrofit. Я нашел только образец Google ToDo, в котором сопрограммы используются для одноразовой выборки, а затем вручную обновлять данные при изменении.
2 ответа
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
, вышеперечисленное не может быть достигнуто напрямую!
Поэтому рекомендуется сохранить поток на уровне репозитория и сделать liveata мостом между пользовательским интерфейсом и репозиторием!
Главное отличие в том, что flow
есть несколько операторов, которые livedata
нет! Но опять же, вам решать, как вы хотите построить свой проект!
Как следует из названия, вы можете думать о 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
Учитывая, что Flow является частью Kotlin, а LiveData - частью библиотеки androidx.lifecycle, я думаю, что Flow используется как часть вариантов использования в чистой архитектуре (без зависимостей от фреймворка).
LiveData, с другой стороны, учитывает жизненный цикл, поэтому соответствует ViewModel.
На данный момент вся моя архитектура использует liveata, но Flow выглядит интересной темой для изучения и принятия.