🐕

結局Coroutines FlowはLiveDataより強いのか

2021/11/04に公開

前置き

※長らく下書きにあったのをポストした記事なので細かい考察はありません🙇‍♂️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側で受け取れることです。

コールドストリームなので、次々と状態変化が起きても無駄なくスレッドを使い破棄もしてくれます。

さまざまな演算子

mapfilteronEachreduceなど、LiveDataには無い多くの演算子で効率的なデータ変換を標準サポートしてくれます。

テスタビリティ

テストのしやすさもFlowに軍配が上がります。

LiveData+Coroutinesのテストはピタゴラスイッチのようなもので、他のテストの干渉を受けないよう上手く作らないとFailが起きたり、observeのチェーンになってしまいます。

FlowではflowOnする際のdispatcherTestCoroutineDispatcherを使い、runBlockingTestで走らせることで必ず決まった順序でテストが可能なので、無用意な影響を排除できます。

その順序をチェックするcollectIndexedなど便利なオペレーターも揃ってます。

一部だけモックをDIすることも容易です。

まとめ

LiveDataからFlowに移行すると、無駄のない非同期処理が書けて、いろんな演算子も使え、テストも捗る!

ただし、FlowはAndroidではなくKotlinの機能なので、Androidで使う場合flowWithLifecycleとかの導入を忘れないようにしましょう。

あと、LiveDataより強いのかどうかですが、作ろうとしてるモノが何か次第だと思います。上記のメリットを生かせると判断すれば完全Flowで、確信がなければ最初はLiveData+Flowという判断で良いと思います。asLiveDataみたいなご配慮オペレーターも用意されてますしね。

Discussion