Android liveData源码解析

一.LiveData是什么?
LiveData是一种可感知生命周期的组件,在Activity\Fragment\Service等组件都处于活跃可见的状态的时候,才去更新app的页面的
优点不会造成内存泄漏等

二.LiveData使用
添加依赖

api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
api "androidx.lifecycle:lifecycle-extensions:2.2.0"

为了方便我就写一个单例

object MyLiveData {
   val liveData by lazy { MutableLiveData<String>() }
}

setValue是主线程中使用,postValue异步线程使用

MyLiveData.liveData.value="1233"

订阅消息

MyLiveData.liveData.observe(this,{
           Toast.makeText(this,it,Toast.LENGTH_LONG).show()
       })

三.源码分析
1.LiveData,observe

@MainThread
  public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
      assertMainThread("observe");//检查线程
//这行代码可以先去了解下Lifecycle的源码分析,这段代码的意思就是拿到当前的状态和DESTROYED做比较,如果相等的话return 就不会触发onChanged方法
      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;
      }
    //可以去参考lifecycle源码分析,目的就是观察生命周期
      owner.getLifecycle().addObserver(wrapper);
  } 

我们看到这个方法只传了两个参数,第一个参数是owner,第二个参数是observer.首先第一个参数为什么传this就可以了?因为
ComponentActivity实现LifecycleOwner接口,具体的可以去看Lifecycle的源码分析,第二个参数也就是一个接口
2.LiveData.LifecycleBoundObserver

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
       @NonNull
       final LifecycleOwner mOwner;
 
       LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
           super(observer);
           mOwner = owner;
       }

       @Override      //只有当页面可见的时候返回为true
       boolean shouldBeActive() {
           return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
       }

       @Override  //执行每个生命周期函数都会回调这个函数
       public void onStateChanged(@NonNull LifecycleOwner source,
               @NonNull Lifecycle.Event event) {
           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);
       }
   }

LifecycleBoundObserver把我们传进来的LifecycleOwner和观察者Observer做了一个保存.也就是它是对LifecycleOwner和Observer做了一次封装,onStateChanged执行每个生命周期函数都会回调这个函数的,why?为什么呢! 这里大致总结一下
在ComponentActivity里面初始化了LifecycleRegistry并且创建了一个透明的Fragment,在Fragment里面的每个生命周期函数里面都会调用相应的dispatch方法,例如(Lifecycle.Event.ON_START),最终分发到LifecycleEventObserver.onStateChanged方法.
LifecycleBoundObserver 这个实现了LifecycleEventObserver接口,所以会分发到到这个方法

3.LifecycleBoundObserver.onStateChanged
activeStateChanged(shouldBeActive()) shouldBeActive只有当状态是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(this);
           }
       }

dispatchingValue(this),在LiveData.setValue方法中dispatchingValue传入的是null

//不管是initiator 等不等于null  最后都会把观察者包装器initiator传了considerNotify方法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
       if (mDispatchingValue) { //默认情况下是false
           mDispatchInvalidated = true;
           return;
       }
       mDispatchingValue = true;
       do {
           mDispatchInvalidated = false;
           if (initiator != null) {
               considerNotify(initiator);
               initiator = null;
           } else {
               //调用initiator=null的情况下是执行下面的循环 遍历过个观察者
               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里面传入了this,然后进行循环,这时候if (initiator != null) 满足条件就会调用considerNotify方法

   private void considerNotify(ObserverWrapper observer) {
       if (!observer.mActive) { //如果不是存活状态的话就return
           return;
       }
       if (!observer.shouldBeActive()) {
           observer.activeStateChanged(false);
           return;
       }
       if (observer.mLastVersion >= mVersion) {
           return;
       }
       observer.mLastVersion = mVersion;
       observer.mObserver.onChanged((T) mData);
   }

有没有很奇怪为什么又来判断一次 if (!observer.shouldBeActive()) 并且调用了 observer.activeStateChanged(false),这个目的就是为了进一步确认是否是可见状态,因为你的activity可能突然一下不可见了,例如你切换到后台了这时候不可见了,这时候是需要调用这个方法进行拿到页面是否可见

if (observer.mLastVersion >= mVersion)这行代码的意思决定着粘性事件的分发.什么是粘性事件? 粘性事件就是:先liveData.value设置数据,然后再去注册liveData.observe 这个就加做粘性事件!,如果不需要粘性事件,可以通过反射来让他们相等
observer.mLastVersion(观察者)默认是-1,而mVersion默认情况下是0,当你调用LiveData.value的set方法时候就会进行++一次 .假如现在是先调用LiveData.setValue,mVersion++了一次.这时候是mVersion等于1,然后在注册liveData.observe ,这时候observer.mLastVersion还没有进行赋值还是-1
,所以这时候 if (observer.mLastVersion >= mVersion) 不满足条件,最后调用了observer.mObserver.onChanged方法,这个onChanged,就是我们在observe的时候传入的第二个参数,所以就能拿到数据了

总结:
1.在observe(this,observer)方法创建一个LifecycleBoundObserver,这LifecycleBoundObserver继承ObserverWrapper实现了LifecycleEventObserver接口,在LifecycleBoundObserver里面对LifecycleOwner和observer进行了保存
2.当activity生命周期发生变化的时候会执行LifecycleBoundObserver.onStateChanged,那是因为ComponentActivity里面初始化了LifecycleRegistry并且创建了一个透明的Fragment,在Fragment里面的就可以感应activity每个生命周期函数,并且里面都会调用相应的dispatch方法,例如(Lifecycle.Event.ON_START),最终分发到LifecycleEventObserver.onStateChanged方法
3.如果发现mActive是tue的话才会observer.onChanged方法,只有当onStart和onResume的时候mActive才会为tue

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容