MVVM 完全に理解した - 1
LiveData について調べたこと。
Observer パターンと総称型(ジェネリクス)について知っていると幸せになれるかもしれません。
LiveData とは
LiveData is an observable data holder class.
監視可能なデータホルダークラス、だそうです。
内部的に Observer パターンを適用しており、値が更新されると紐づいた Activity や Fragment に逐次通知し、かつそれらのライフサイクルに応じて、通知を柔軟に制御(停止・再開)してくれる仕組みです。
Observer パターン分からない民は、拙著にGoF本に沿って Observer パターン実装した例があるのでぜひ読んでみてください。PDF版もあるよ(ダイマ
関係する派生クラスなど
いずれも、package android.arch.lifecycle
- LiveData ( abstract class )
- MutableLiveData ( extends LiveData )
- MediatorLiveData ( extends LiveData )
- Observer ( interface )
MutableLiveData と MediatorLiveData はそれぞれ LiveData を継承した具象クラスです。
MVVM アーキテクチャで意識するのは MutableLiveData および Observer でしょうかね。
MediatorLiveData は読んで字のごとく Mediator パターンを採用していて、LiveData をまとめて制御したいときに使えそうです。Mediator パターンも嫌いじゃない。
かなりざっくりな流れ
適当に LiveData オブジェクトを作って、内部を探ってみました。
LiveData#observe(owner, observer) //通知先の owner と、 処理内容 observer を登録 ↓ LiveData#setValue(value) // setValue がコールされると、LiveData の値が更新される or LiveData#postValue(value) //非同期処理用 ↓ LiveData#dispatchingValue(null) // setValue の中でコール。値を発行(dispatch) ↓ LiveData#considerNotify(initiator) // notify メソッドにより登録された observer に通知 ↓ 紐づいたオブジェクトに更新通知
observe
メソッドで Activity や Fragment を実体とする owner
と、onChange
を実装した Observer
オブジェクト、または匿名メソッドを渡します。匿名メソッドはKotlinならSAM変換が使えるのでワンライナーで実装できますね!!便利!!(急なテンションの上昇)
observe
メソッド内部では owner
と observer
とをひとまとめにした LifecycleBoundObserver
が生成されており、ここで observer
と Activity 等が紐づけされ、ライフサイクルに応じて onChange
が呼ばれたり呼ばれなかったりするようです。
まとめ
LiveData は、ライフサイクルを意識しないでデータの通知とかを行えるすごいやつ。
次は ViewModel について調べる。
※ご注意※
ここから先は途中まで書いて挫折し、しかし消すには忍びなかったただの乱文です。結論がないのであしからず。
インターフェース
LiveData……の代わりに、MutableLiveData の主なインターフェースを見てみます。たぶん普段使うのもこれだと思います。
MutableLiveData は setValue / postValue
のアクセスが public
になっているので、外部から値を渡して更新することができます。
observe (@NonNull LifecycleOwner owner, @NonNull Observer observer)
唐突に出てきた LifecycleOwner
インターフェース奴、getLifecycle
というメソッドを実装します。
よって、実態は Activity
や Fragment
といったライフサイクルを持つものになります。
一方、第二引数は Observer
インターフェースが渡されています。
Observer
インターフェースは次のメソッドを実装します。
fun onChange( T t )
observe
メソッドの実装は次のとおり。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } owner.getLifecycle().addObserver(wrapper); }
必要なとこだけギュッッッってします。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); //① owner.getLifecycle().addObserver(wrapper); //② }
① private で保持しているコレクション mObservers
に、observer
と wrapper: LifecycleBoundObserver
を put しています。
② 次に、owner
に wrapper
を追加しています。
wrapper
は owner
と observer
とをひとつにまとめたオブジェクトで、ライフサイクルを持ったオブジェクト(Activity, Fragment)と observer
とを紐づけているようです。
observe
メソッドにより、この LiveData
オブジェクトに onChange
メソッドが呼べるオブジェクト Observer
が追加されました。
紐づいた値が更新されると、この Observer
オブジェクトの onChange
メソッドが随時コールされる形になります。