web-dev-qa-db-ja.com

Kotlin FlowとLiveData

前回のGoogle I/Oでは、Jose AlcerrecaとYigit Boyar 教えてください LiveDataを使用してデータをフェッチする必要はなくなりました。ここで、ワンショットフェッチの中断関数を使用し、Kotlinのフローを使用してデータストリームを作成する必要があります。コルーチンはワンショットフェッチや挿入などの他のCRUD操作に最適であることには同意します。ただし、データストリームが必要な場合、Flowがどのような利点をもたらすかわかりません。 LiveDataも同じことをしているようです。

フローの例:

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サンプル のみが見つかりました。コルーチンはワンショットフェッチに使用され、変更時に手動でデータを再フェッチします。

10
Dmitry Simakov

Flowは_reactive stream_の一種です(rxjavaのように)。 _.map_、buffer()などのさまざまな演算子がたくさんあります(いずれにせよ、rxJavaに比べて演算子の数が少ない)。したがって、LiveDataFlowの主な違いの1つは、他のスレッドでマップ_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 )
_

LiveDatamapを使用すると、上記を直接達成することはできません。

したがって、リポジトリレベルでフローを維持し、livedataをUIとリポジトリの間のブリッジにすることをお勧めします。

主な違いは、flowにはlivedataにはないさまざまな演算子がたくさんあることです。しかし、繰り返しますが、どのようにしてプロジェクトを構築したいのでしょうか。

3
Santanu Sur

名前が示すように、Flowは、非同期に計算された複数の値の連続したフローのようなものと考えることができます。私の観点から見ると、LiveDataとFlowの主な違いは、すべてのデータがフェッチされて一度にすべての値が返されるとLiveDataが更新されるのに対して、Flowは継続的に結果を出力することです。あなたの例では、単一の値をフェッチしていますが、これは、私の考えでは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の重要な特徴は、それが収集されたときにのみビルダーコード(ここではレンダー関数)が実行されるため、そのcoldストリームであることです。

Asynchronous Flow にあるドキュメントを参照することもできます

3
nulldroid