LoginSignup
9
1

More than 5 years have passed since last update.

ViewDataBinding.setLifecycleOwner() しないと LiveData が更新されなかった

Last updated at Posted at 2018-11-07

Databinding、便利ですよね。本格的に使うのは初めてなのですが、もっと早く導入しておけばよかったと思います。

前置きはさておき、下記コードをご覧下さい。

HogeActivity.kt
    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() を見てみます。

LiveData.java
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

dispatchingValue() という部分が怪しいですね。

LiveData.java
    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 が登録される場所を探してみました。

LiveData.java
    @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() はちゃんと呼びましょう、ということで。

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1