LiveData的分析与简单使用

  • 简介

    • LiveData是androidx.lifecycle-livedata包下的一个抽象类,实现了一种关联了生命周期的简单观察者模式,主要的功能就是用于视图层与数据间的单向一对多通知,一个LiveData会持有一个可观察的Data对象,一开始是处于NOT_SET状态,当用户通过setValue方法更新后,LiveData会遍历所有的observer(处于Active状态的),通知他们Data的更新.LiveData的行为会在Lifecycle范围内,避免很多Activity Leak和空指针
      本文代码样例都是kotlin,LiveData的源码是java
  • LiveData的使用

      //声明一个LiveData
      val data:MutableLiveData = MutableLiveData()
      //在需要的地方订阅,observer的onChange方法会回调
      data.observe(lifecycleOwner,observer)
      //可以和retrofit配合使用
     interface ApiService {
        @GET("/api/get")
        fun getChannels():LiveData>>
      }
      //可以和room配合使用
      @Dao
     interface BorrowModelDao {
    
          @Query("select * from s_borrow_moel")
         fun getAllBorrowedItems(): LiveData>
    
      }
      //配合ViewModel保存数据/监听数据更改
      class MyViewModel:ViewModel(){
        val data:MutableLiveData = MutableLiveData()
      }
    复制代码
  • LiveData Tricks

    • Transformations.map方法转换LiveData的数据类型
      比如我们用Retrofit获取了一个User类数据:LiveData,但是我们只想把User.name暴露给外部观察者,那么我们可以这样操作
    private val userLiveData:MutableLiveData = MutableLiveData()
    val userNames:LiveData = Transformations
    .map(userLiveData){
        user ->
        user.name
    }
    复制代码

    Transformations在androidx.lifecycle包下

    • MediatorLiveData
      MediatorLiveData可以同时观察多个LiveData的变化
        //声明
        val mediatorLiveData:MediatorLiveData = MediatorLiveData()
        //其他合适的地方添加source
        mediatorLiveData.addSource(stringFromNetwork){
            mediatorLiveData.value = it
        }
        mediatorLiveData.addSource(stringFromDatabase){
            mediatorLiveData.value = it
        }
      复制代码
  • 配合ViewModel使用

    • 我们知道ViewModel可以在一个LifecycleOwneronCreateOnDestroy之间保存实例不受到屏幕旋转等ConfigChange的影响
      所以可以通过Activity/Fragment持有ViewModel,而ViewModel持有各类LiveData,Activity/Fragment注册观察需要的数据,实现数据与UI的同步,而且不会因此发生Activity泄漏,甚至可以用ViewModel来进行Activity/Fragment之间的通讯
  • 关于Lifecycle

    • Lifecycle组成

      • LifecycleOwner: Activity/Fragment都是LifecycleOwner(support包下的AppCompatActivity和对应的Fragment),他是androidx.lifecycle:lifecycle-common包下的一个借口,只有getLifecycle()一个方法,返回一个Lifecycle对象
      • Lifecycle: 而这个Lifecycle就是维护生命周期state的主体,默认实现是LifecycleRegistry,这个说起来也挺长的,以后有空再新的文章里仔细说明,反正现在读者只要知道我们常用的AppCompatActivity/Fragment都是可以拿到生命周期Lifecycle的就行了
      • LifecycleObserver: 也是一个接口,不过它一个抽象方法也没有,如果我们需要一个新的自定义的观察 者,只要实现这个接口,然后在需要对应生命周期方法回调的方法上添加
        OnLifecycleEvent注解并添加对应注解就好了,LiveData有一个 LifecycleBoundObserver内部类实现了这个接口,不过继承关系是这样的 LifecycleObserver <--GenericLifecycleObserver <- LifecycleBoundObserver,
        LifecycleBoundObserver会在onStateChange收到回调,不依赖于注解,不过读 者现在只要知道在Lifecyclestate发生改变的时候,LifecycleObserver会收 到通知(void onStateChanged(LifecycleOwner source, Lifecycle.Event event);)

  • LiveData类分析

    • 简单的类结构
      有几个内部类,都是ObserverWrapper的子类,用于普通的观察者(带生命周期)的LifecycleBounderObserver,和不带的AlwaysActiveObserver..
      abstract class LiveDate{
    
        class LifecycleBounderObserver extends ObserverWrapper implements GenericLifecycleObserver{
    
        }
    
        private abstract ObserverWrapper{
    
        }
    
        private class AlwaysActiveObserver extends ObserverWrapper {
    
        }
      }
    复制代码
  • observe入手分析

    • 传入参数: LifecycleOwner , Observer类(简单的回调通知接口)
    • 首先通过LifecycleOwner获取Lifecycle,判断时候是DESTROYED状态,是的话直接return 将ObserverLifecycleOwner包装为LifecycleBoundObserver对象
    • LiveData维护了一个SafeIterableMap, ObserverWrapper> 对象mObservers,保存了Observer和对应的Wrapper,存入LifecycleBoundObserver对象后判断是否已存在并且是否对应当前LifecycleOwner,做出相应的处理,当mObservers中没有时,直接给LifecycleOwner的Lifecycle注册该LifecycleBoundObserver
    • 所以说实际上是我们传入的LifecycleOwner保存的Lifecycle注册了一个观察者,LifecycleBoundObserver会在state 等于 DESTROYED的时候移除该观察者,在其他状态的时候调用activeStateChange()方法
    • 先比较当前mActive和新active,赋值给mActive,然后通过LiveData类的mActivieCount是否为0来判断是不是完全没有通知过,如果是进入非active状态mActiveCount就-1,否则+1,原先未active现在active了,调用onActive方法,新的mActivieCount == 0并且 新active的状态为false就调用onInactive方法,然后判断mActive,true则会调用dispatchValue方法,基本上mActivieCount只会有0 -> 1 ,1 -> 0两个状态变化,所以onActive是LiveData观察者数量从无到有时回调,onInactive反之
      private abstract class ObserverWrapper {
       final Observersuper T> mObserver;
       boolean mActive;
       int mLastVersion = START_VERSION;
       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(this);
           }
       }
      复制代码

} ```

  • 上面罗里吧嗦一大推读者可能一脸懵逼,反正结论就是,LiveData状态由没有观察者到有观察者会走onActive方法,反之会走onInactive方法,不管原先状态如何,只要新状态是活跃就会走dispatchValue
  • onInactive/onActiveLiveData里两个open protected的方法,只在MediatorLiveData里有实现,我还没有仔细研究MediatorLiveData,大家可以去看看源码
  • 所以LifecycleBoundObserver新状态为活跃时,会调用外部类LiveDatadispatchValue方法,传入的参数为ObserverWrapper,也就是LifecycleBoundObserver的父类(LifecycleBoundObserver继承了ObserverWrapper,实现了GenericLifecycleObserver),在这要注意下内部类(非静态)是可以拿到外部类实例的,LiveData.this.XXX,忘记的同学复习下,我是好久没用java,突然看到有点懵逼..
//传入参数是Observer,有的话就分发给它,为null就对所有Observers分发数据
void dispatchingValue(@Nullable ObserverWrapper initiator) {
  //如果正在分发数据,就标记为分发无效,分发中的会因此跳出循环
   if (mDispatchingValue) {
     //标记为分发无效
       mDispatchInvalidated = true;
       return;
   }
   //标记为分发中
   mDispatchingValue = true;
   do {
       mDispatchInvalidated = false;
       if (initiator != null) {
           considerNotify(initiator);
           initiator = null;
       } else {
           for (Iteratorsuper T>, ObserverWrapper>> iterator =
                   mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                //尝试分发
               considerNotify(iterator.next().getValue());
               //标记为无效时会跳出循环,在while循环中等待一次mDispatchInvalidated再次变为true时再次进入for循环
               if (mDispatchInvalidated) {
                   break;
               }
           }
       }
       //没有被标记无效时while循环就执行一次完事,否则会再次执行
   } while (mDispatchInvalidated);
   mDispatchingValue = false;
}
复制代码
  • LiveData中的mDispatchingValue/mDispatchInvalidated在此处保证不会重复分发或者分发旧的value,当setValue分发调用dispatchValue(null)时会遍历所有的Observer分发新值,否则只分发给传入的ObserverWrapper,这里说明下:LiveData维护了mDispatchingValue/mDispatchInvalidated,而Observer可能会有多个,都持有LiveData对象(因为是内部类),所以等待的observer对应的LiveData会获得mDispatchInvalidated = true,中断进行中的分发,让旧数据不再分发
  • considerNotify: 第一步检查ObserverWrapper是否mActive,第二步检查shouldBeActive(),第三步检查ObserverWrapper的版本observer.mLastVersion >= mVersion,最后才通知更新,调用Observer的onChange方法
  • ObserverWrapper中的mLastVersion /和LiveData的mVersion用来防止再入活跃状态后重复分发
  • ObserverWrapper中的mActive用来控制该观察者是否需要分发(activeStateChanged(boolean)方法的作用下)
  • considerNotify方法

    先上代码
    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;
         //noinspection unchecked
         observer.mObserver.onChanged((T) mData);
     }
    
    复制代码
    很简单的逻辑,就是
    1. 第一步判断是否active,这个mActive属性在几种情况下会为true
      a. Observer是通过observeForever注册的
      b. Observer的shouldBeActive返回true 我们看看方法代码,只有绑定的Lifecycle的State大于STARTED才会为true
            @Override
            boolean shouldBeActive() {
                return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
            }
复制代码
mActive会在生命周期变化时会被多次检查
2. 第二步再次检查`shouldBeActive()`状态
3. 第三步检查`mLastVersion`和`mVersion`  
    这个version是在setValue时被+1的,检查一下防止重复分发,完成后修改lastVersion然后回调`onChange(T)`
复制代码
  • setValue/postValue方法的分析

    按惯例先看看代码,postValue的代码也好理解,只是给赋值操作加了一个锁,并把setValue放到主线程执行,使多个postValue只有最后一个的value生效

    private final Runnable mPostValueRunnable = new Runnable() {
       @Override
       public void run() {
           Object newValue;
           synchronized (mDataLock) {
               newValue = mPendingData;
               mPendingData = NOT_SET;
           }
           //noinspection unchecked
           setValue((T) newValue);
       }
    };
    protected void postValue(T value) {
       boolean postTask;
       synchronized (mDataLock) {
           postTask = mPendingData == NOT_SET;
           mPendingData = value;
       }
       if (!postTask) {
           return;
       }
       ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    复制代码

    想象一下如果两个线程T-A,T-B 里都执行了postValue传入不同的值A,B,先会在方法内的mDataLock锁住的代码块竞争执行,比如A先执行,mPendingData先被赋值为A,postTask => true,然后赋值为B,也就是说第一次的赋值才会通过同步块之后的if判断,执行分发runnable,线程T-B只是修改了mPendingValue的值

    然后会有一个主线程上的同步代码块(也是同一个锁),将新值执行setValue,mPendingValue重设为初始值,也就是说取得值实际上是后一个线程的B,后面分发完成重设为NOT_SET,后面的PostValue又进入原来的逻辑了

    postValue的注释也很清楚了: If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.

  • 基本流程

    • observe() -> 新建Observer -> Observer的StateChange -> dispatchValue -> considerNotify
    • setValue/postValue -> dispatchValue -> considerNotify
  • 总结

    LiveData的结构是比较简单的,使用时注意不要多次注册观察者,一般如果在Activity中使用,就在OnCreate方法注册,Activity被关闭或回收后观察者会自动解除订阅,所以不会发生泄漏,我们也可以自己继承LiveData做更多的定制来实现自己的业务逻辑,配合Tranformations工具类和MediatorLiveData可以实现很多比较复杂的逻辑

转载于:https://juejin.im/post/5c40381af265da61561f82a1

你可能感兴趣的:(LiveData的分析与简单使用)