Jetpack架构组件库-LiveData工作原理只一篇你就懂

推荐阅读:

heiyulong,公众号:Android进化之路Jetpack架构组件库-LiveData只一篇你就会用

前言

本次主要讲解的内容:

1、LiveData 核心方法

2、LiveData 原理解析

3、LiveData粘性事件产生的原因

一、LiveData 核心方法:

1、LiveData 公开(public)方法
T getValue()
//返回当前值。请注意,在后台线程上调用此方法不能保证将接收到最新的值集。
boolean hasActiveObservers()
//如果此LiveData具有活动的观察者,则返回true。
boolean hasObservers()
//如果此LiveData具有观察者,则返回true。
void observe(LifecycleOwner owner, Observer<T> observer)
//(注册和宿主生命周期关联的观察者)将给定的观察者添加到给定所有者的生存期内的观察者列表中。
void observeForever(Observer<T> observer)
//(注册观察者,不会反注册,需自行维护)将给定的观察者添加到观察者列表中。
void removeObserver(Observer<T> observer)
//从观察者列表中删除给定的观察者。
void removeObservers(LifecycleOwner owner)
//删除所有与给定绑定的观察者LifecycleOwner。
2、LiveData 受保护(protected)方法
void onActive()
//(当且仅当有一个活跃的观察者时会触发)当活动观察者的数量从0变为1时调用。
void onInactive()
//(不存在活跃的观察者时会触发)当活动观察者的数量从1变为0时调用。

//这并不意味着没有观察者,可能仍然有观察者,但是它们的生命周期状态不是STARTED或RESUMED (如后退堆栈中的“Avtivity”)。

//您可以通过来检查是否有观察者hasObservers()。
void postValue(T value)
//(和setValue一样。不受线程环境限制,)将任务发布到主线程以设置给定值。
void setValue(T value)
//(发送数据,没有活跃的观察者时不分发。只能在主线程。)设置值。

二、LiveData 原理解析:

1、observe订阅源码分析

LiveData 注册观察者触发消息分发流程原理分析

1.1首先看看observe方法源码

observe 注册时,可以主动跟宿主生命周期绑定,不用反注册:

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //1. 断言,这个方法只能在主线程调用(如果不在主线程注册会抛IllegalStateException异常)
    assertMainThread("observe");
    //2.当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //3.创建生命周期感知的观察者包装类(把注册进来的observer包装成 一个具有生命周边边界的观察者)
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //4.接着会判断该观察是否已经注册过了,如果是则抛异常,所以要注意,不允许重复注册
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    //5.对应观察者只能与一个owner绑定
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //6.利用Lifecycle,把观察者注册到LifecycleBoundObserver进去,就能监听到宿主生命周期状态的变化
    owner.getLifecycle().addObserver(wrapper);
}

总结:

  • 1、observe只能在主线程调用,如果不在主线程注册会抛IllegalStateException异常

  • 2、当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求

  • 3、内部会创建生命周期感知的观察者包装类LifecycleBoundObserver(把注册进来的observer包装成 一个具有生命周边边界的观察者)

  • 4、对应观察者只能与一个owner绑定,不允许重复注册

  • 5、最后利用Lifecycle,把观察者注册到LifecycleBoundObserver进去,就能监听到宿主生命周期状态的变化

LifecycleBoundObserver到底承载了哪些信息,接着看...

1.2、LifecycleBoundObserver源码:

从上面的分析可以看出:

利用Lifecycle,把观察者注册到LifecycleBoundObserver进去,这样监听到宿主生命周期状态的变化

一旦一个新的观察者被添加,Lifecycle也会同步它的状态和宿主一致,此时会触发观察者的onStateChanged方法

  • 内部会创建生命周期感知的观察者包装类LifecycleBoundObserver(把注册进来的observer包装成 一个具有生命周边边界的观察者)

    • 它能监听宿主被销毁的事件,从而主动的把自己反注册,避免内存泄漏

    • 此时观察者是否处于活跃状态就等于宿主是否可见, 监听宿主的生命周期,并且宿主不可见时不分发任何数据

LifecycleBoundObserver源码:
//1、LifecycleBoundObserver是LiveData内部类
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        //2、观察者是否活跃就等于宿主的状态是否大于等于STARTED;
        //如果页面当前不可见,你发送了一条消息,此时是不会被分发的,可以避免后台任务抢占资源,当页面恢复可见才会分发。
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        //3、如果当接收到 DESTROYED 的事件会自动解除跟 owner 的绑定
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        //否则说明宿主的状态发生了变化,此时会判断宿主是否处于活跃状态
        activeStateChanged(shouldBeActive());
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

//接口,触发观察者的onStateChanged方法
//通过Lifecycle,addObserver(Observer oberver)
//handleLifecycleEvent(Event event)
//宿主(Activity 或 Fragment)每次生命周期变化都会回调onStateChange方法
public interface LifecycleEventObserver extends LifecycleObserver {
    /**
     * Called when a state transition event happens.
     *
     * @param source The source of the event
     * @param event The event
     */
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
ObserverWrapper 状态变更后,如果观察者处于活跃状态会触发数据的分发流程
//抽象类
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    //ObserverWrapper在每次注册的时候都会重新new,所以mLastVersion每次都是-1开始。
    int mLastVersion = START_VERSION;//这里就等于-1

    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer;
    }

    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        //更改观察者的状态
        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        //1、如果此时有且只有一个活跃的观察者则触发onActive
        if (wasInactive && mActive) {
            onActive();
        }
        //2、没有任何一个活跃的观察者则触发onInactive
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }
        //3、如果此时观察者处于活跃状态,下面就开始分发数据了
        if (mActive) {
            dispatchingValue(this);
        }
    }
}
dispatchingValue(this)数据分发流程控制:(内部执行considerNotify(initiator)方法)
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            //1、如果传递的观察者不为空,则把数据分发给他自己。这个流程是新注册观察者的时候会被触发
            considerNotify(initiator);
            initiator = null;
        } else {
            //2、否则遍历集合中所有已注册的的观察者,逐个调用considerNotify,分发数据
            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 数据真正分发的地方:
private void considerNotify(ObserverWrapper observer) {
    //1、观察者当前状态不活跃就不分发
    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.
    //2、观察者所在宿主是否处于活跃状态,否则不分发,并且更改观察者的状态为false
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    //3、此处判断观察者接收消息的次数是否大于等于 发送消息的次数(observer被创建之初verison=-1 )
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    //4、计算最新的发送消息的次数
    observer.mLastVersion = mVersion;
    //5、这里会执行传入的observer的onChanged方法
    observer.mObserver.onChanged((T) mData);
}
2、setValue发送源码分析
2.1 setValue源码分析
@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        //这个mVersion是属于LiveData的,然后只在setValue(postValue最终也会调用setValue)的时候会自增1
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
2.2同上observer分析,dispatchingValue(this)数据分发流程控制:(内部执行considerNotify(initiator)方法)
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            //1、如果传递的观察者不为空,则把数据分发给他自己。这个流程是新注册观察者的时候会被触发
            considerNotify(initiator);
            initiator = null;
        } else {
            //2、否则遍历集合中所有已注册的的观察者,逐个调用considerNotify,分发数据
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}
2.3、considerNotify 数据真正分发的地方:
private void considerNotify(ObserverWrapper observer) {
    //1、观察者当前状态不活跃就不分发
    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.
    //2、观察者所在宿主是否处于活跃状态,否则不分发,并且更改观察者的状态为false
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    //3、此处判断观察者接收消息的次数是否大于等于 发送消息的次数(observer被创建之初verison=-1 )
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    //4、计算最新的发送消息的次数
    observer.mLastVersion = mVersion;
    //5、这里会执行传入的observer的onChanged方法
    observer.mObserver.onChanged((T) mData);
}
  • 综上分析:LiveData的粘性事件

    这种情况被称为LiveData的粘性事件

    • 通过同一个LiveData

    • 在更改数据的时候调用setValue(postValue最终也会调用setValue)的时候内部维护的mVersion会自增1,mVersion初始值是-1

    • 在监听数据变化的时候,既调用observer监听的时候,每次内部都会在通过包装类中new ObserverWrapper,内部维护了一个mLastVersion变量,mLastVersion也是初始值为-1,所以注意了,每执行一次observer方法内部维护mLastVersion都会新创建而变为-1

    • 结论所以只要之前有发射过一次数据,那么后面注册的观察者都会接收到之前发射过的数据

这也是为什么通常使用LiveData时,在大多数情况下,应用组件的 onCreate() 方法是开始观察 LiveData 对象的正确着手点,就是为了避免粘性事件的发生。

< END >

【Android进化之路】

微信扫描二维码,关注我的公众号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值