Jetpack ——LiveData初识到源码解析(一)

上篇博客分享了下Lifecycle,使用的技术也就是:观察者模式+注解+反射。本篇博客继续学习Jetpack的LiveData,其实这个东西是一种可观察的数据存储类。

LiveData自己可以作为观察者,观察到数据变化,并回调给开发者。 它是可以监听到Activity(Fragment)生命周期的变化,并且在Activity处于活跃状态下,才发送时间通知开发者处理业务逻辑。

LiveData官网

这个LiveData不是数据,是数据存储类。

LiveData的使用

示例:一个按钮,一个TextView , 点击一个按钮,TextView的值+1。

LiveData一般是结合ViewModel使用的,关于ViewModel,之后的博客再分享。 先创建一个类继承自ViewModel:

/**
 * author: liumengqiang
 * Date : 2020/5/14
 * Description :
 */
public class NameViewModel extends ViewModel {

	//MutableLiveData继承自LiveData
    private MutableLiveData<String> name;

	//暴露获取方法
    public MutableLiveData<String> getName() {
        if(name == null) {
            name = new MutableLiveData<>();
        }
        return name;
    }
}

使用的话就很简单了, 在Activity的onCreate方法中:

    private int index = 0;

    private TextView nameTextView;

    private Button btn;

    private NameViewModel nameViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_data);
		//获取或者创建ViewModel
        nameViewModel =
                new ViewModelProvider(this,
                        new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(NameViewModel.class);

		//绑定LiveData到一个观察者上
        nameViewModel.getName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                nameTextView.setText(s);
            }
        });

        nameTextView = findViewById(R.id.live_data_text);
        btn = findViewById(R.id.live_data_btn);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            	//数据源改变
                String name = "hello world " + (index ++);
                nameViewModel.getName().setValue(name);
            }
        });
    }

这个代码就很简单了,结果如下图:

这个例子是很简单的,LiveData强大之处就是: 既可以作为观察者,也可以作为被观察者。

作为观察者:能够感知Activity或者Fragment的生命周期的变化。
作为被观察者:当数据改变能够通知给开发者,以处理业务逻辑。

其内部原理是怎样的呢?

LiveData源码分析

在分析源码之前我们看三个结论,

  • LiveData是能够感知组件生命周期的,当Activity处于活跃状态时,才能够收到数据,不处于活跃状态是收不到事件的。
  • LiveData在组件处于DESTROYED状态下会移除Observer,解除绑定,避免内存泄漏
  • 每次调用setValue更改数据源之后,如果组件从非活跃状态到活跃状态,组件此时接收到的是最新的数据,而中间发的很多的次变更都是无效的。

首先我们从订阅开始:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    	//检测是否在主线程
        assertMainThread("observe");
        //判断组件是否是DESTROYED状态。
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //将组件和Observer封装成一个对象:LifecycleBoundObserver
        //这个对象实现了LifecycleObserver接口
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //把所有的Observer和封装的对象添加到了集合中
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
       	......
       	//这个是把LifecycleObserver实现对象和 组件绑定起来
       	//这样就能够感知组件的生命周期了。
        owner.getLifecycle().addObserver(wrapper);
    }

这里做了主要三件事

  1. 检测组件是否是处于DESTORYED状态, 如果是,就直接返回
  2. 将组件和Observer封装成了一个LifecycleObserver实现类对象,这个对象,存到了一个map中,这样方便之后setValue分发数据
  3. 最后将LifecycleObserver实现类对象和组件绑定在一起,这样能够感知组件的生命周期变化了。

现在看下setValue方法,也就是改变LiveData里面的数据源

	//从这个注解可以看出来必须要在主线程调用
    @MainThread
    protected void setValue(T value) {
    	// 检测是否在主线程
        assertMainThread("setValue");
        //定义了一个版本号
        mVersion++;
        //将值赋值给mData变量
        mData = value;
       	//开始分发数据事件
        dispatchingValue(null);
    }

代码注释比较清晰了,主要是这个版本号:mVersion是个什么东西呢? 为什么定义这个东西呢? mVersion就是记录一下改变次数,每次setValue方法调用,也就是每次数据源改变,mVersion都会+1, 这个值接下来会和LifecycleBoundObserver实现类的mLastVersion对比的,具体下文解释。

然后将value值赋值给了mData对象,这样的话,试想一下,如果若此调用setValue方法,每次set 的值都不一样,那么是不是mData存储的都是最后一次setValue的值呢? 答案是肯定的,存储的就是最后一次setValue的值。

然后现在开始分发数据源改变的事件:

   @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
      ........
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
            	//initiator不是null, 也就是定向分发事件,
                considerNotify(initiator);
                initiator = null;
            } else {
            	//initiator是null
            	//	循环之前map, 然后给每个观察者都分发事件
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

由于此时传入的dispatchingValue传入的参数是null,所以是全部的观察者都分发事件。

传入initiator不是null的情况是在生命周期改变的情况下执行的,下文具体分析

    private void considerNotify(ObserverWrapper observer) {
        //判断是否是处于活跃状态
        //是否是已经解绑
        if (!observer.mActive) {
            return;
        }
        //活跃状态是:STARTED或者RESUMED
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //判断Observer的mLastVersion和mVersion的大小
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //给Observer的mLastVersion重新赋值
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        //执行观察者的onChaned回调
        observer.mObserver.onChanged((T) mData);
    }

这里的ObserverWrapper observer对象实际上就是LifecycleBoundObserver, 这个在刚开始订阅的时候内部创建的。它继承自ObserverWrapper

LifecycleBoundObserver也实现了GenericLifecycleObserver,而GenericLifecycleObserver继承自LifecycleEventObserver, 这个细节很重要,具体后续的代码会着重分析。

   class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

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

		//判断是否是活跃状态:STARTED或者RESUMED,
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

		//这个方法就是组件生命周期改变时, 调用的方法。传入的参数一个是组件本身,一个是组件处于的状态
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        	//当组件处于DESTROYED状态时,也就是处于销毁状态时
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            	//移除Observer,解除绑定
                removeObserver(mObserver);
                return;
            }
            //这个方法的实现是在父类ObserverWrapper中的
            activeStateChanged(shouldBeActive());
        }

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

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

从LifecycleBoundObserver的具体实现,需要注意两个知识点

  1. shouldBeActive方法是返回组件是否:STARTED或者RESUMED状态,如果是就返回true
  2. onStateChanged方法是分析LiveData感知组件生命周期的重要点,具体我们下文分析。

在onStateChanged方法中调用了父类的activeStateChanged方法,看下具体实现:

       void activeStateChanged(boolean newActive) {
       		//判断活跃状态是否等于上一次的状态
            if (newActive == mActive) {
                return;
            }
            ......
           //
            if (mActive) {
            	//如果是活跃状态,那么就分发数据源改变事件,传入的参数是自己本身,
            	//也就是:LifecycleBoundObserver类的对象
                dispatchingValue(this);
            }
        }
    }

这时候对于dispatchingValue方法传入的参数不是null, 是不是就是单次分发呢? 懵逼的,重新网上看下dispatchingValue方法。,进入到了if判断里面。

重新回到considerNotify方法,mLastVersion和mVersion的初始值都是-1, 但是每次setValue, mVersion的值都会+1, 但是mLastVersion的值还是-1, 所以(observer.mLastVersion >= mVersion) 不成立,将mVersion的值赋值给mLastVersion, 这样mLastVersion就是最新的值了, 最后调用了我们熟悉的onChanged方法。

想一下considerNotify方法中为什么会有这三个if判断呢?
首先前两个判断就是要保证组件处于活跃状态; 此三个判断就是要保证只接受最后一次的新数据,并且只执行一次。 Google这样设计也是相当的巧妙!

这样每次setValue 到 执行onChange方法流程就分析完了。

那么它是怎样感知生命周期的呢? 换句话说就是LifecycleBoundObserver的onStateChanged方法是什么时候执行的呢?

这个问题,如果是看过Lifecycle源码的,这个问题是相当简单的。

Lifecycle源码分析

记不记得我们刚开始调用LiveData的observe方法的时候,该方法的最后一句话:

owner.getLifecycle().addObserver(wrapper);

把封装成的LifecycleBoundObserver类对象和组件绑定到了一块, 这样内部就通过 ReportFragment就能够感知生命周期的变化了。详见:Lifecycle源码分析

这里需要注意的一点是,当生命周期变化的时候,最终调用的dispatchEvent方法:

    static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
        	//这里返回的直接是将observer转成了LifecycleEventObserver。
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            //调用了观察者的onStateChanged方法
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

这里的observer参数就是LifecycleBoundObserver类对象,上文说过LifecycleBoundObserver实现了LifecycleEventObserver接口,Lifecycling.lifecycleEventObserver(observer);内部执行一通逻辑之后,做的操作是直接将observer转成了LifecycleEventObserver接口对象。

ReportFragment生命周期的变化之后,调用的是LifecycleBoundObserver的onStateChanged方法,这样是不是形成了闭环?!

重新理一下步骤:

setValue ——> onChanged流程

  1. 通过调用LiveData的observe方法,创建了LifecycleBoundObserver对象,并且绑定了组件和LifecycleBoundObserver实例。
  2. 每次setValue之后会调用dispatchingValue方法
  3. 在dispatchingValue方法内,会调用considerNotify方法
  4. 在considerNotify方法内,回到用观察者的onChanged方法。

感知LiveData生命周期流程

  1. 通过调用LiveData的observe方法, 在这个方法最后一句话,绑定了组件和LifecycleBoundObserver类的实例对象。
  2. LifecycleRegister的addObserver方法内,将LifecycleBoundObserver类实例存储到了一个map中。
  3. 在组件的内部创建了一个空白的ReportFragment, ReportFragment的生命周期是和组件的生命周期是同步的。
  4. 以Report Fragment的onStart方法为例: 内部调用了dispatch(Lifecycle.Event.ON_START);
  5. dispatch方法内调用handleLifecycleEvent方法, 该方法是在LifecycleRegister类内部的
  6. handleLifecycleEvent ——》 moveToState ——》 sync ——》 forwardPass ——》 dispatchEvent ——》 mLifecycleObserver.onStateChanged
  7. 最后回到了LifecycleBoundObserver的onStateChanged方法内,调用:activeStateChanged方法
  8. activeStateChanged ——》 dispatchingValue ——》 considerNotify ——》onChanged方法

这样整个流程就完全了, 可能感知生命周期的流程比较懵逼的话,一定要看一下:Lifecycle源码分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章