Kotlin Coroutinesの進化はすざましく、とどまるところを知りません。
状態やイベントを扱いやすくなったStateFlowやSharedFlowが登場し、さらには、Lifecycleをより扱いやすくなったLifecycleOwner.addRepeatingJobやLifecycleOwner.repeatOnLifecycle、Flow.flowWithLifecycleが追加されました。
RoomやDataStore等Jetpackの各種ライブラリでもCoroutinesが使われており、Jetpack Composeでも様々なところでCoroutinesが活用されています。
そういった中で、一部LiveDataやRxJavaからCoroutinesに書き直す動きが見られ、多少混乱を招いていると感じています。
結論から言うと、現時点において積極的にCoroutinesに移行する必要性はないと考えています。
今回は、それらを比較しつつ、どういった使い分けをするのが好ましいのか私の視点からまとめます。
軽く特徴を紹介します。
LiveData
はJetpackライブラリ群の一つです。
Lifecycle
を考慮したObservable
であり、onStop
時に自動で購読を解除してくれ、onStart
時に再開をしてくれます。
値を保持することに特化しており、購読時に最新の値を通知してくれます。
そのため、イベント通知にはそのまま使うことは出来ません。
Flow
はKotlin Coroutines
において値を複数回送信することができるInterface
です。
状態を表現するためのStateFlow
や、イベント通知のためのSharedFlow
が存在します。
Kotlin Coroutines
のsuspend function
やChannel
とも当然相性が良いです。
RxJava
はReactiveX
のJava
実装です。
ReactiveX
はStreamを用いて非同期かつイベントベースのプログラミングを実現するためのライブラリです。
様々な言語で利用可能になっています。
Kotlinへの拡張を持ったRxKotlin
も提供されています。
それぞれを各観点から比較します。
非同期処理をAndroidアプリ開発で扱うにおいて、困難なポイントにLifecycleがあります。
安易に非同期処理を扱うと、onDestory
以降でView
を参照してクラッシュしたり、バックグラウンドになっているのにも関わらず不要にリソースを消費する可能性があります。
LiveData
は強力にLifecycle
をサポートします。
Flow
に関してはlivedata-ktx
にてlaunchWhenStarted等のLifecycle
に従うツールが提供されています。
しかし、launchWhenStarted
をFlow
に対して使う際は、バッファに関して注意が必要です。
それの課題を解決し、より扱いやすくしたLifecycleOwner.addRepeatingJob
、LifecycleOwner.repeatOnLifecycle
、Flow.flowWithLifecycle
が登場しましたが、まだα版での提供になっています。
2021-04-06 追記
RxJava
のLifecycle
の対応はRxLifecycle等のサードパーティのツールを使うことで行うことが出来ます。
DataBinding
はxml
から値を参照することで、コード量を削減することが出来ます。
LiveData
はDataBinding
に対応しています。
Flow
はStateFlow
を使うことでDataBinding
で扱うことが出来ますが、まだCanary版のみになっています。
RxJava
はDataBinding
に対応しておらず、ObservableFieldかLiveData
に変換する必要があります。
LiveData
とRxJava
はJava
から利用が可能です。
Flow
はKotlin
からのみ利用ができ、Java
からは使うことは出来ません。
Flow
はKotlin
で書かれているため、完全にNull安全です。
また、RxJava
もNull安全で扱えます。
LiveData
はLintでチェックできるようになりましたが、完全にNull安全と言えるかというと、少し難しいところがありそうです。
Flow
はKotlin Multiplatform
に対応しており、AndroidとiOSのコードを一部共通化することが可能です。
RxJava
はReactiveX
に準拠したRxSwiftやRxDartが存在し、複数プラットフォームで似たような記述が可能です。
Flow
はまだまだ成長途中のため、今後破壊的変更や大幅な機能追加も考えられます。
RxJava
やLiveData
はかなり安定してきていると考えられるでしょう。
RxJava
はオペレータの数が膨大で、かなり複雑に感じます。
Flow
はRxJava
と似ている部分も多いですが、一度のみ値を返すsuspend function
は非常にシンプルで、比較するとRxJava
より洗練されてると言えるでしょう。
LiveData
は複雑な機能は殆どないので、一番シンプルだと思います。
一方で、機能の豊富さという観点から見ると、逆の結果になるでしょう。
LiveData
はJetpack
の各種ライブラリと相性が良く、必要なことはほぼほぼできると思います。
Flow
はJetpackライブラリ群でも力を入れて支援をしています。
まだまだ発展途上ですが、今後より使いやすくなっていくことでしょう。
RxJava
は周辺ライブラリの開発も活発で、多くのツールが存在します。
一方で、Google公式によるサポートはあまり無いように感じます。
また、Kotlin Coroutines
の発展とともに、最近は下火になっている印象があります。
LiveData
、Flow
、RxJava
ともにJetpack ComposeのStateに変換可能なオペレータが用意されています。
どれを利用していても、Jetpack Composeは利用可能です。
一方で、Coroutinesに対応したrememberCoroutineScopeやLaunchedEffect等のAPIが存在し、若干Coroutinesに軍配が上がりそうです。
上記を表にすると、以下のようになるでしょう
LiveData | Flow | RxJava | |
---|---|---|---|
Lifecycle | ◎ | ◯ | ◯ |
DataBinding | ◎ | ◯ | ✕ |
Javaからの利用 | ◎ | ✕ | ◎ |
Null安全 | △ | ◎ | ◎ |
マルチプラットフォーム | ✕ | ◯ | ◯ |
安定性 | ◯ | △ | ◯ |
複雑性 | ◎ | ◯ | △ |
機能の豊富さ | △ | ◯ | ◎ |
外部ツールとの連携 | ◯ | ◯ | ◯ |
Jetpack Composeとの相性 | ◯ | ◎ | ◯ |
様々な観点から3つを比較してきましたが、一長一短といったところで、今の所これが良い、これは悪い、みたいなところは無いと思います。
それぞれの長所、短所を理解した上で、自分のプロジェクトにあったツールを採用することが大事です。
強いて言うのであれば、やはりFlow
は今後より発展が見込めるため、新規プロジェクトで採用したり、LiveData
やRxJava
から徐々に移行していくことは悪い選択肢ではないと思います。
データレイヤーでの取り扱いや、イベント通知等を含め、統一感のあるコードを書くことが可能になります。
一方で、α版でのみ提供されている機能があったり、今後大きな変更がある可能性を考えると、多少慎重になる必要があるでしょう。
また、個人的にLiveData
のシンプルさは好きです。
シンプルなプロジェクトであれば、新規プロジェクトであってもLiveData
を中心に組むと良いと思います。
RxJava
は複数プラットフォームで似た書き方ができるという大きな特徴があります。
ReactiveX
の思想でコーディングするためには、RxJava
が必須です。
冒頭にも言いましたが、現段階においてCoroutines
に積極的に置き換える理由はないでしょう。
複数の書き方が入り交じるプロジェクトは、理解が困難になり、不具合も入り込みやすくなります。
引き続きLiveData
、RxJava
を使い続けることは、それもまた非常に良い選択です。
選択肢が多いと悩みがちですが、各々にとって一番使いやすいツールが見つかることを祈っています。
Kotlin Coroutinesの解説本をZennにて販売しています。より詳しく学びたい方は、こちらも合わせて確認してみて下さい。