日々是好日

プログラミングについてのあれこれ、ムダ知識など

MVVM 完全に理解した - 1

LiveData について調べたこと。
Observer パターンと総称型(ジェネリクス)について知っていると幸せになれるかもしれません。

LiveData とは

LiveData  |  Android Developers

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 メソッド内部では ownerobserver とをひとまとめにした LifecycleBoundObserver が生成されており、ここで observer と Activity 等が紐づけされ、ライフサイクルに応じて onChange が呼ばれたり呼ばれなかったりするようです。

まとめ

LiveData は、ライフサイクルを意識しないでデータの通知とかを行えるすごいやつ。
次は ViewModel について調べる。


※ご注意※
ここから先は途中まで書いて挫折し、しかし消すには忍びなかったただの乱文です。結論がないのであしからず。

インターフェース

LiveData……の代わりに、MutableLiveData の主なインターフェースを見てみます。たぶん普段使うのもこれだと思います。
MutableLiveData は setValue / postValue のアクセスが public になっているので、外部から値を渡して更新することができます。

observe (@NonNull LifecycleOwner owner, @NonNull Observer observer)

唐突に出てきた LifecycleOwner インターフェース奴、getLifecycle というメソッドを実装します。
よって、実態は ActivityFragment といったライフサイクルを持つものになります。

一方、第二引数は 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 に、observerwrapper: LifecycleBoundObserver を put しています。 ② 次に、ownerwrapper を追加しています。

wrapperownerobserver とをひとつにまとめたオブジェクトで、ライフサイクルを持ったオブジェクト(Activity, Fragment)と observer とを紐づけているようです。

observe メソッドにより、この LiveData オブジェクトに onChange メソッドが呼べるオブジェクト Observer が追加されました。
紐づいた値が更新されると、この Observer オブジェクトの onChange メソッドが随時コールされる形になります。