LiveData
をイベントの通知(トーストやダイアログを表示指示)として利用する、いわゆるLiveEvent
の実装をまとめました。
どれを使えばいいの?
結論から先に言うと、hadilq/LiveEventまたは最初の値を無視を使うといいと思います。その他に紹介しているSingleLiveEvent、Event、SingleLiveEvent2は実装に問題があるので使わないほうがいいです。
SingleLiveEvent
architecture-samplesのTODOアプリで昔使われていたやつ。MutableLiveData
を継承しsetValue()
等で設定された値は一度だけonChanged()
に流れることを保証するクラス。
問題点
複数Observer
が存在する場合に、一つのObserver
だけにしか値が流れない。
Event
SingleLiveEvent
の改良。MutableLiveData
を継承した独自クラスではなく、通常のLiveData
にEvent
でラップした値を流す。
https://github.com/android/architecture-samples/blob/todo-mvvm-live-kotlin/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/Event.kt
https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150
改善点
一度だけ値を取得できるgetContentIfNotHandled()
と常に値を取得できるpeekContent()
の2種類のインターフェースを提供することで、Viewにイベントを通知しつつLoggerで毎回値を取得するようなユースケースは達成できるようになった。
問題点
SingleLiveEvent
と同じく、イベントとして購読したいObserver
が2つ以上ある場合には利用できない。
値をラップしないと使えないので若干冗長。
SingleLiveEvent2
SingleLiveEvent
の改良。MutableLiveData
を継承した独自クラスでObserver
のMutableSet
を管理し、全てのObserver
に対して一度だけonChanged()
が呼ばれるようにする。
改善点
Event
で実現できない複数Observer
に対するイベントの通知を実現。
問題点
最初に購読したLifecycleOwner
のライフサイクルに、その後購読した全てのObserver
が従ってしまう。
最初の値を無視
LiveData
でイベントを扱った時に起こる問題は最新の値がキャッシュされることに起因するので、それを排除するというアプローチ。LiveData
とobserve()
の両方を拡張関数で手を入れることでキャッシュされる値を無視する。
利点
シンプルな拡張でイベントの通知を実現。
問題点
LiveData
とobserve()
の両方が正しく揃うことで動作するので、他の実装に比べてバグが混入しやすい。
hadilq/LiveEvent
MediatorLiveData
を継承した独自クラスの内部でObserver
をラップするObserverWrapper
を生成、その中で一度だけのイベント通知を実現している。
利点
ライブラリとして簡単に利用できる。
問題点
無さそうに思える。
まとめ
手法 | 複数Observer対応 | イベントが発生した後の購読で値が流れない |
---|---|---|
SingleLiveEvent | × | × |
Event | △ | × |
SingleLiveEvent2 | ○ | ○ |
最初の値を無視 | ○ | ○ |
hadilq/LiveEvent | ○ | ○ |