LiveData 源码解析

简单介绍

LiveData 是一个基于观察者模式的组件,在 Android JetPack 组件中的一部分,在开发中非常实用。LiveData 就是一个数据持有类,可以分发数据,由于内部封装了生命周期回调,所以只会在适当的生命周期中回调数据,而不会在监听者销毁后回调而导致异常。

下面我们就用一个简单的例子来分析一下 LiveData 的源码吧。

相同页面传值

我们首先在onCreate方法中进行监听,通过点击按钮改变数据,可以看到,每次改变数据后我们的回调都会打印。

LiveDataTest.getLiveData().observe(this, {
    Log.d("TAG", "MainActivity $it")
})
btnFirst.setOnClickListener {
    LiveDataTest.setData("1")
}
// MainActivity 1

我们首先来看observe方法,首先校验是否是主线程,如果宿主已经处于DESTROYED生命周期,则直接返回。接着将宿主和回调方法封装成LifecycleBoundObserver,然后保存回调方法和封装的wrappermObservers里面,如果回调方法已经存在且宿主不一致,说明重复提交,则会报错。如果只是回调方法存在,则直接返回。否则调用addObserver方法,让wrapper和宿主生命周期绑定。

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();
​
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    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);
}

接着我们看setValue的调用逻辑,也是需要在主线程调用,如果需要在子线程调用可以使用postValue方法。接着将版本号自增,修改mData的值,然后调用dispatchingValue(null)方法进行数据的方法。

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

我们继续看dispatchingValue方法,由于我们的入参是null所以会走到 for 循环里面调用considerNotify方法通知回调方法。

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

considerNotify方法中,如果宿主不是活跃状态,则不会通知。然后再次检测宿主状态,接着检测版本号,然后赋值新的版本号,然后调用回调的onChanged方法。

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // notify for a more predictable notification order.
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

不同页面传值

我们接着上面的例子,增加第二个页面,在第二个页面修改值,这是第一个页面不会收到回调方法,因为状态已经是非活跃了;接着退回到第一个页面,可以看到这时第一个页面的回调方法会被调用,因为状态已经变成活跃了。

第一个情况很好解答,因为在considerNotify方法的第一行就做了处理,如果是非活跃的则不会回调了。第二个情况中,我们并没有再次注册,就说明LiveData已经监听了我们的生命周期了,我们来到LifecycleBoundObserver的类里面,可见我们宿主状态改变时会回调到onStateChanged方法,这里面对于我们宿主的生命周期做了处理,如果已经处于销毁状态了,就会移除。如果状态改变并且是成为活跃状态了,则会调用数据回调方法,这也就解释了我们的第二种情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值