JetPack--LiveData

发布时间:2024年01月23日

一、前言

????????Lifecycle 能够感知宿主生命周期变化的组件
????????基于生命周期消息分发订阅的能力,向当前宿主LifecycleOwner 注册一个observer ,宿主每一次生命周期的变化都会回调给观察者的onStateChanged方法,即便是刚刚注册的观察者,宿主也会回调它的onStateChanged方法,会有状态同步的过程
????????LiveData 利用了这个能力,巧妙的实现了当宿主销毁的时候自动移除自动注册进来的observer ,从而避免了手动注册的麻烦,不会造成内存泄漏

二、定义

????????LiveData组件是Jetpack新推出的基于观察者的消息订阅/分发组件,具有宿主(Activity、Fragment)生命周期感知能力,这种感知能力可确保 LiveData 仅分发消息给处于活跃状态的观察者,只有处于活跃状态的观察者才能收到消息

活跃状态:0bserver所在宿主处于started,resumed状态

? 三、与handler发送消息的比较

handler发送消息:

  • 消耗资源:无论当前页面是否可见,都会分发消息
  • 可能导致内存泄漏:无论当前宿主是否还存活,都会分发消息
  • 无论页面可见不可见,都会去执行页面刷新,IO操作。还可能会弹出对话框
    Handler handler = new Handler(){
    @Override
    public void handleMessage(@NonNull Message msg){

    };

    handler.sendMessage(msg)

LiveData:

  • 减少资源占用:页面不可见时不会派发消息
  • 确保页面始终保持最新状态:页面可见时,会立刻派发最新的一条消息给所有观察者,保证页面最新状态
  • 避免NPE:不需要手动处理生命周期
  • 取代eventbus:可以打造一款不用反注册,不会内存泄漏的消息总线
    liveData,observer(this,new Observer<User>){
        void onChanged(User user){
        }
    }

    liveData.postValue(data);

四、用法

  • MutableLiveData

????????使用继承自LiveData的MutableLiveData做消息分发,使用单一开闭原则,只有MutableLiveData擦可以发送消息

????????LiveData 对象只能接收消息,避免拿到 LiveData 对象时既能发消息也能收消息的混乱使用

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value){
        super.postValue(value);
    }
    
    @0verride
    public void setValue(T value) {
        super.setValue(value);
    }
}
  • MediatorLiveData

可以统一观察多个LiveData发射的数据进行统一的处理,同时也可以做为一个LiveData,被其他Observer观察

LiveData<Integer> liveDatal = new MutableLiveData();
LiveData<Integer> liveData2 = new MutableLiveData();

MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>(),

liveDataMerger.addSource(liveData1, observer);
liveDataMerger,addSource(liveData2, observer);

Observer observer = new Observer<Integer>(){
    @0verride
    public void onChanged(@Nullable Integer s){
        mTv.setText(s):
    }
}
  • Transformations.map 操作符

可以对livedata的进行变化,并且返回一个新的livedata对象

MutableLiveData<Integer> data = new MutableLiveData<>();
//数据转换
LiveData<String> transformData = Transformations,map(data, input -> String.valueOf(input)
//使用转换后生成的transformData去观察数据
transformData.observe(this, output -> {
});
//使用原始的livedata发送数据
data.setValue(10);

五、核心方法

  • observe(LifecycleOwner owner,Observerobserver):注册和宿主生命周期关联的观察者
  • observeForever(Observer observer):注册观察者,不会反注册,需自行维护
  • setValue(T data):发送数据,没有活跃的观察者时不分发,只能在主线程
  • postValue(T data):发送数据,不受线程限制
  • onActive:当且仅当有一个活跃的观察者时会触发
  • inActive:不存在活跃的观察者时会触发

六、核心逻辑

1.黏性消息分发流程

即新注册的observer也能接收到前面发送的最后一条数据

  1. 调用observer方法向LiveData注册观察者,并将传递进来observer包装成LifecycleBoundObserver
  2. 初次注册,宿主每次生命周期的变化都会回调onStateChanged方法
  3. 在onStateChanged方法中,宿主被销败,则从LiveData移除该观察者,流程结束
  4. 如果宿主的状态为started、resumed,则分发最新数据到每个观察者
  5. 调用dispatchingValue(Observer observer)分发数据,如果observer为空,则分发数据给LiveData中存储的所有观察者,如果不为空,则分发数据给该observe
  6. 接下来调用considerNotify(Observer observer)进行分发前的判断,如果观察者所在的宿主不活跃了,不分发;如果observer.version >= LiveData.version 不分发;满足条件调用observer.onStateChanged(data)分发数据

2.普通消息分发流程

即调用postValue,setValue才会触发消息的分发

  • postValue:该方法可以在子线程,使用handler.post先发送到主线程.再分发消息
  • setValue:mVersion++,记录当前发送的消息的次数,用于和observer的version作比对,防止消息重复
  • dispatchingValue:此时会遍历mObservers集合中所有观察者,逐一调用considerNotify真正的分发消息
  • considerNotify:1.宿主不活跃了不分发,2.已经接收过了不分发,observer.version >= livedata.version

七、源码分析

调用observe方法将传递进来的observers对象包装成了一个LifecycleBoundObserver对象

然后保存到mObservers这个Map集合中,有消息时遍历这个集合去分发

调用observerForever方法会被包装成AlwaysActiveObserve对象,

LifecycleBoundObserver:具有生命周期感知的观察者,是LifecycleEventObserver 的子类

AlwaysActiveObserve:在他的方法里shouldBeActive 永远为true,不管宿主是否处于可见状态,都可以接收数据,处理场景,即便是在后台也要处理一些事情,一定要在宿主被销毁时进行反注册

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        // 若LifecycleOwner被销毁,则忽略该observer
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
 
        // 将LifecycleOwner和Observer封装成具有生命周期感知的LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 避免重复添加相同的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;
        }
 
        // 把这个LifecycleBoundObserver对象注册到Lifecycle宿主的生命周期里
        owner.getLifecycle().addObserver(wrapper);
    }
 
    // 无视生命周期, 每次数据发生变化时,都会回调通知 Observer
    // 需要手动在不需要时移除 Observer
    @MainThread
    public void observeForever(@NonNull Observer<T> observer) {
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }
 

然后把这个LifecycleBoundObserver对象注册到Lifecycle宿主的生命周期里,这个对象就能接收到宿主生命周期变化事件,每一次事件的通知都会回调到LifecycleBoundObserver的onStartChanged方法

//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和resume
        //观察者是否活跃相当于宿主是否活跃,也就是宿主的状态是否大于等于STARTED;
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }
 
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        //当接收到宿主生命周期的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);
    }
}

首先会判断状态是否等于DESTROYED,如果宿主被销毁了,调用removeObserver(mObserver)主动执行反注册,从LiveData中把这个observer 移除掉,主动避免了内存泄漏的问题
如果宿主没有被销毁,宿主状态发生别的变化,就会触发activeStateChanged方法,并且通过shouldBeActive 方法判断观察者是否处于活跃的状态,也就是判断当前宿主是否处于活跃状态,是否处于可见状态

shouldBeActive:
????????Lifecycle 的 STATE 为 STARTED/RESUMED 则返回 true,表示处于活跃状态

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;
    if(wasInactive && mActive){
        onActive();
    }
    if(LiveData.this.mActiveCount == 0 && !mActive){
        onInactive();
    }

    if (mActive){
        dispatchingValue(initiator: this);
    }
}

在activeStateChanged方法中,首先判断activeCount是否等于0,如果等于0就说明LiveData 中没有任何的观察者处于活跃状态,

如果当且仅当有一个观察者的时候就会触发onActive 方法,

如果没有任何一个活跃的观察者就会触发onInactive方法,

当前观察者处于活跃状态,就会调用dispatchingValue 进行数据分发,把自己传递了进去
首先判断传递的参数是否为空,不为空就把数据分发给自己,如果为空,就是从setValue过来的,说明有了新的数据,此时需要把Observers 集合中所有的观察者进行遍历,把数据分发给它们
最终都会调用considerNotify 做真正的分发

//1、在宿主生命周期发生变化的时候。回调LifecycleBoundObserver的onStateChanged方法。最后会调到这个方法,传入this(LifecycleBoundObserver)
//2、在setValue的时候调用。传入null;
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 当前正在处于分发数据中   直接return,继续之前的分发
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        //宿主生命周期状态变化initiator != null; setValue时initiator = null;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            //迭代通知每个符合条件的观察者,调用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;
}

先根据shouldBeActive判断观察者是否处于活跃的状态,也就是宿主是否可见
接着判断observer 的lastVersion是否大于等于LiveData的version 避免数据的重复发送,每次生命周期的变化都会走到这里,但是LiveData 发送几次,每个观察者就能接收几次,不然就会重复了
如果条件都满足就会执行observer包装的mObservers的onChanged方法,并对齐observer的lastVersion和LiveData的version字段

private void considerNotify(ObserverWrapper observer) {
        // 如果当前不是处于活跃状态,就停止
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //判断观察者的最新版本号是否不小于LiveData的当前版本号 
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //将livedata的version赋值给observer的version
        observer.mLastVersion = mVersion;
        // 回调出去
        observer.mObserver.onChanged((T) mData);
    }

PostValue 中需要用到handler post 到主线程,最终调用setValue?
在这个方法中会讲LiveData 的version 字段+1
接下来调用dispatchChangeValue 并传递null

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

八、总结:

????????把注册进来的Lifecycle包装成LifecycleBoundObserver储存起来,然后利用Lifecycle的能力,当宿主的状态发生变化时都会回调LifecycleBoundObserver的onStateChanged 方法,在这里就会去判断每个观察者是否处于活跃状态,

????????对于使用Observer 方法注册的观察者而言是否处于活跃状态就相当于宿主是否处于活跃状态,如果使用ObserverForever注册的观察者,会一直处于活跃状态,即便页面处于不可见了,它也能够接收到数据。
????????LiveData 不仅能满足现有的事件分发能力,还能实现高性能的事件分发机制
????????LiveData 的version字段和Observer 的lastVsesion 字段,默认情况下在刚开始创建时都等于-1 ,如果liveData 已经发送了数据,它的version就会加1,这个时候如果新注册这个Observer 在触发消息分发的时候,这两个version 字段就不相等了,这个Observer 就能接收到之前发送的消息

文章来源:https://blog.csdn.net/weixin_42277946/article/details/135739499
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。