結局Coroutines FlowはLiveDataより強いのか
前置き
※長らく下書きにあったのをポストした記事なので細かい考察はありません🙇♂️3分で読める記事です。
Android界隈でCoroutines Flowが出てLiveDataやRxJavaからの置き換えが少しずつ進んでいますが、Flowの何が良いのかわかってないまま周りに釣られてやってる方も少なくないと思います。
私も最初はその1人だったので、Flowを使うメリットで思いつくものをまとめました。
以前Qiitaで初学者向けFlowを書きましたが、今回は違う切り口からです。
従来手法の問題点
まず、Rx系を使う上で避けては通れない問題が、OSのライフサイクルへの適合やオーバーヘッド対策を盛り込むこと、あるいはそれらの考慮抜けによるバグです。
LiveDataはAndroid Jetpackの一部なので、Androidのライフサイクルやメモリ/キャッシュとの親和性は抜群です。これは初心者のぶっつけ実装でもその類のバグが起きにくいことでLiveDataの優秀さを実感できると思います。もちろんLifecycleOwnerの指定間違いみたいなのは致命的です。
一方、次々と起こる状態変化のsubscribeや、Model→ViewModelのデータ変換部分に注目すると、そこは複雑化やバグの温床を抱えたままです。
Flow移行のメリット
構造化された並行性
FlowにあってLiveDataにない主な1つは、mapの再計算やデータ変換をflowOn
により簡単に他スレッドへ投げ、結果だけUI側で受け取れることです。
コールドストリームなので、次々と状態変化が起きても無駄なくスレッドを使い破棄もしてくれます。
さまざまな演算子
map
、filter
、onEach
、reduce
など、LiveDataには無い多くの演算子で効率的なデータ変換を標準サポートしてくれます。
テスタビリティ
テストのしやすさもFlowに軍配が上がります。
LiveData+Coroutinesのテストはピタゴラスイッチのようなもので、他のテストの干渉を受けないよう上手く作らないとFailが起きたり、observe
のチェーンになってしまいます。
FlowではflowOn
する際のdispatcher
にTestCoroutineDispatcher
を使い、runBlockingTest
で走らせることで必ず決まった順序でテストが可能なので、無用意な影響を排除できます。
その順序をチェックするcollectIndexed
など便利なオペレーターも揃ってます。
一部だけモックをDIすることも容易です。
まとめ
LiveDataからFlowに移行すると、無駄のない非同期処理が書けて、いろんな演算子も使え、テストも捗る!
ただし、FlowはAndroidではなくKotlinの機能なので、Androidで使う場合flowWithLifecycle
とかの導入を忘れないようにしましょう。
あと、LiveDataより強いのかどうかですが、作ろうとしてるモノが何か次第だと思います。上記のメリットを生かせると判断すれば完全Flowで、確信がなければ最初はLiveData+Flowという判断で良いと思います。asLiveData
みたいなご配慮オペレーターも用意されてますしね。
Discussion