Databinding、便利ですよね。本格的に使うのは初めてなのですが、もっと早く導入しておけばよかったと思います。
前置きはさておき、下記コードをご覧下さい。
binding = DataBindingUtil.setContentView<ActivityHogeBinding>(this, R.layout.activity_hoge).apply {
setLifecycleOwner(this@HogeActivity) // ★★★これ!
viewModel = ViewModelProviders.of(this@HogeActivity).get(HogeActivityViewModel::class.java)
}
「★★★これ!」の部分を書いてないと、ViewModel の LiveData にデータをセットしても、GUI に反映されません。自分はこれに気づかず、一時間くらい悩みました。ちょっと悔しかったので、なぜ反映されないのか?を軽く調べました。
LiveData に値を設定するときは、setValue() か postValue()(メインスレッドで setValue() してくれる) を使うと思います。ということで setValue() を見てみます。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
dispatchingValue() という部分が怪しいですね。
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
//
// 中略
//
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
//
// 中略
//
inititator とやらは null なはずなので、else のほうに入ります。デバッガで見てみたところ、ここの mObervers が 0 になっていました。なので、considerNotify() まで到達しないですね。
mObserves が登録される場所を探してみました。
@MainThread
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);
//
// 中略
//
}
mObservers.putIfAbsent() で無事に増えています。言い換えれば、observe() が呼ばれないと増えないわけです。
ところで、observe() の引数に、LifecycleOwner が出てきました。@NonNull 指定なので、(バグってなければ)LifecycleOwner が入っていないと呼ばれることはないはずですね。なので、最初の「★★★これ!」を怠ると、LiveData が更新されない、ということにつながります。
せっかくなので、ViewDataBinding.setLifecycleOwner() を読み進めましたが、思いのほかあちこちに飛ぶので、すっきりしませんが、また機会があれば調べたいと思います。結論としては、setLifecycleOwner() はちゃんと呼びましょう、ということで。