美文网首页Android开发
LiveData详细分析

LiveData详细分析

作者: 杨充211 | 来源:发表于2020-03-05 20:18 被阅读0次

    目录介绍

    • 01.LiveData是什么东西
    • 02.使用LiveData的优势
    • 03.使用LiveData的步骤
    • 04.简单使用LiveData
    • 05.observe()和observerForever()
    • 06.LiveData原理介绍
    • 07.observe订阅源码分析
    • 08.setValue发送源码分析
    • 09.observeForever源码
    • 10.LiveData源码总结

    00.使用LiveData实现bus事件总线

    • 利用LiveData实现事件总线,替代EventBus。充分利用了生命周期感知功能,可以在activities, fragments, 或者 services生命周期是活跃状态时更新这些组件。支持发送普通事件,也可以发送粘性事件;还可以发送延迟消息,以及轮训延迟消息等等。
    • https://github.com/yangchong211/YCLiveDataBus

    01.LiveData是什么东西

    • 基于观察者模式
      • LiveData是一种持有可被观察数据的类。LiveData需要一个观察者对象,一般是Observer类的具体实现。当观察者的生命周期处于STARTED或RESUMED状态时,LiveData会通知观察者数据变化。
    • 感知生命周期
      • 和其他可被观察的类不同的是,LiveData是有生命周期感知能力的,这意味着它可以在activities, fragments, 或者 services生命周期是活跃状态时更新这些组件。那么什么是活跃状态呢?就是STARTED和RESUMED就是活跃状态,只有在这两个状态下LiveData是会通知数据变化的。
    • 自动解除数据订阅
      • 要想使用LiveData(或者这种有可被观察数据能力的类)就必须配合实现了LifecycleOwner的对象使用。在这种情况下,当对应的生命周期对象DESTORY时,才能移除观察者。这对Activity或者Fragment来说显得尤为重要,因为他们可以在生命周期结束的时候立刻解除对数据的订阅,从而避免内存泄漏等问题。

    02.使用LiveData的优势

    2.1 具有很明显的优点

    • UI和实时数据保持一致
      • 因为LiveData采用的是观察者模式,这样一来就可以在数据发生改变时获得通知,更新UI。
    • 不会发生内存泄露
      • 观察者被绑定到组件的生命周期上,当被绑定的组件销毁(onDestroy)时,观察者会立刻自动清理自身的数据。
    • 不会再产生由于Activity处于stop状态而引起的崩溃
      • 例如:当Activity处于后台状态时,是不会收到LiveData的任何事件的。
    • 不需要再解决生命周期带来的问题
      • LiveData可以感知被绑定的组件的生命周期,只有在活跃状态才会通知数据变化。
    • 实时数据刷新
      • 当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据
    • 解决Configuration Change问题
      • 在屏幕发生旋转或者被回收再次启动,立刻就能收到最新的数据。
    • 数据共享
      • 如果对应的LiveData是单例的话,就能在app的组件间分享数据。这部分详细的信息可以参考继承LiveData

    2.2 细节点补充

    • 组件和数据相关的内容能实时更新,组件在前台的时候能够实时收到数据改变的通知,当组件从后台到前台来时,LiveData能够将最新的数据通知组件,因此保证了组件中和数据相关的内容能够实时更新。
    • 如果横竖屏切换(configuration change)时,不需要额外的处理来保存数据,当屏幕方向变化时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。

    03.使用LiveData的步骤

    • 创建一个持有某种数据类型的LiveData (通常是在ViewModel中)
    • 创建一个定义了onChange()方法的观察者。这个方法是控制LiveData中数据发生变化时,采取什么措施 (比如更新界面)。通常是在UI Controller (Activity/Fragment) 中创建这个观察者。
    • 通过 observe()方法连接观察者和LiveData。observe()方法需要携带一个LifecycleOwner类。这样就可以让观察者订阅LiveData中的数据,实现实时更新。

    04.简单使用LiveData

    4.1 单独使用LiveData

    • 举一个最简单的案例代码:
      liveData = new MutableLiveData<>();
      liveData.observe(this, new Observer<String>() {
          @Override
          public void onChanged(@Nullable final String newText) {
              // 更新数据
              tv3.setText(newText);
          }
      });
      liveData.setValue("小杨真的是一个逗比么");
      
    • 那么上面这一段代码大概是什么意思呢?
      • 首先创建一个 MutableLiveData(LiveData是抽象类)对象 ,通过 observe 方法可以订阅修改数据的通知,通过 postValue()或者 setValue() 方法发送事件更新数据,已经订阅的 Observer 能够得到数据更改的通知,就会回调 onChanged() 方法。

    4.2 使用LiveData配合ViewModel

    • LiveData是一个数据的包装。具体的包装对象可以是任何数据,包括集合。它是一个抽象类,首先先创建一个类实现LiveData。代码如下所示:
      public class TextViewModel extends ViewModel {
      
          /**
           * LiveData是抽象类,MutableLiveData是具体实现类
           */
          private MutableLiveData<String> mCurrentText;
      
          public MutableLiveData<String> getCurrentText() {
              if (mCurrentText == null) {
                  mCurrentText = new MutableLiveData<>();
              }
              return mCurrentText;
          }
      
      }
      
    • 创建一个观察的对象,观察LiveData中的数据。目前在组件的onCreate()方法中开始观察数据,代码如下所示:
      • 思考下,可以在onResume()中调用么,个人觉得不太好。因为系统会多次调用onResume()方法。
      private void initLiveData() {
          // 创建一个持有某种数据类型的LiveData (通常是在ViewModel中)
          model = ViewModelProviders.of(this).get(TextViewModel.class);
          // 创建一个定义了onChange()方法的观察者
          // 开始订阅
          final Observer<String> nameObserver = new Observer<String>() {
              @Override
              public void onChanged(@Nullable final String newText) {
                  // 更新数据
                  tvText.setText(newText);
              }
          };
          // 通过 observe()方法连接观察者和LiveData,注意:observe()方法需要携带一个LifecycleOwner类
          model.getCurrentText().observe(this, nameObserver);
      }
      
    • 然后去创建更新对象数据内容的对象。如何去更新那个文本中的数据呢?代码如下所示:
      • 想要在UI Controller中改变LiveData中的值呢?(比如点击某个Button设置文本内容的更改)。
      • LiveData并没有提供这样的功能,但是Architecture Component提供了MutableLiveData这样一个类,可以通过setValue(T)和postValue(T)方法来修改存储在LiveData中的数据。MutableLiveData是LiveData的一个子类,从名称上也能看出这个类的作用。
      • 调用setValue()方法就可以把LiveData中的值改为 "小杨真的是一个逗比么" 。同样,通过这种方法修改LiveData中的值同样会触发所有对这个数据感兴趣的类。那么setValue()和postValue()有什么不同呢?区别就是setValue()只能在主线程中调用,而postValue()可以在子线程中调用。
      findViewById(R.id.tv_click).setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              count++;
              String text;
              switch (count%5){
                  case 1:
                      text = "小杨真的是一个逗比么";
                      break;
                  case 2:
                      text = "逗比赶紧来star吧";
                      break;
                  case 3:
                      text = "小杨想成为大神";
                      break;
                  case 4:
                      text = "开始刷新数据啦";
                      break;
                  default:
                      text = "变化成默认的数据";
                      break;
              }
              model.getCurrentText().setValue(text);
          }
      });
      

    05.observe()和observerForever()

    • 一般我们使用 LiveData 的 observe(),当数据更新后,LiveData 会通知它的所有活跃的观察者。
      • 与 RxJava 不同的,LiveData 只会通知活跃的观察者,例如 Activity 位于 Destroyed 状态时是不活跃的,因此不会收到通知。
    • 当然我们也可以使用 LiveData 的 observerForever() 方法进行订阅,区别是 observerForever() 不会受到 Activity 等组件的生命周期的影响,只要数据更新就会收到通知。

    06.LiveData原理介绍

    6.1 简单的原理介绍

    • LiveData可对数据进行观测, 并具有生命周期感知能力, 这就意味着当liveData只会在生命周期处于活跃(inActive)的状态下才会去执行观测动作, 而他的能力赋予不能脱离LifeCycle的范围。
    • 需要注意的是,LiveData内维护的mVersion表示的是发送信息的版本,每次发送一次信息, 它都会+1, 而ObserverWrapper内维护的mLastVersion为订阅触发的版本号, 当订阅动作生效的时候, 它的版本号会和发送信息的版本号同步.他们初始值都为-1。

    6.2 然后思考一些问题

    • a.liveData如何实现订阅者模式,如何处理发送事件?
    • b.如何做到感知生命周期的,怎么跟 LifecycleOwner 进行绑定的?
    • c.LiveData 只在 LifecycleOwner active 状态发送通知,是怎么处理的?
    • d.LiveData 会自动在 DESTROY 的状态下取消订阅,是怎么处理的?
    • e.生命周期变化后数据处理流程是怎么样的?
    • f.为什么观察者只能与一个LifecycleOwner绑定,而不是多个?

    07.observe订阅源码分析

    7.1 首先看看observe方法源码

    • 直接查看源代码,如下所示:
      • 当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求,也就是忽略owner的注册;
      • 如果需要与生命周期绑定, 则需要传入LifecycleOwner对象, 将我们的LiveData数据观测者(Observer)包装注册到生命周期的观测者中, 就是源码中创建wrapper对象过程;
      • 需要注意的问题是,不能添加具有不同生命周期的相同观察者,否则就会抛出IllegalArgumentException异常,但是owner可以add多个Observer;
      • 最后添加一个LifecycleObserver,它将在LifecycleOwner更改状态时得到通知,并做出及时的对应更新活动。
      @MainThread
      public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
          //当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求
          if (owner.getLifecycle().getCurrentState() == DESTROYED) {
              // ignore
              return;
          }
          //创建生命周期感知的观察者包装类
          LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
          //如果指定的键尚未与某个值关联,则将其与给定的值关联
          ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
          //对应观察者只能与一个owner绑定
          if (existing != null && !existing.isAttachedTo(owner)) {
              throw new IllegalArgumentException("Cannot add the same observer"
                      + " with different lifecycles");
          }
          if (existing != null) {
              return;
          }
          //lifecycle注册
          //添加一个LifecycleObserver,它将在LifecycleOwner更改状态时得到通知
          owner.getLifecycle().addObserver(wrapper);
      }
      

    7.2 看看LifecycleBoundObserver源码

    • 然后看一下观察者类LifecycleBoundObserver的源代码
      • LifecycleBoundObserver对象, 它继承于ObserverWrapper, 并最终实现了GenericLifecycleObserver接口;
      • 在发生状态转换事件时,会调用onStateChanged方法,在这个方法中,如果是DESTROYED状态,则先要移除观察者,然后在取到生命周期状态变更事件
      class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
          @NonNull final LifecycleOwner mOwner;
      
          LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
              super(observer);
              mOwner = owner;
          }
      
          @Override
          boolean shouldBeActive() {
              return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
          }
      
          @Override
          public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
              if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                  // 当接收到 DESTROYED 的事件会自动解除跟 owner 的绑定
                  removeObserver(mObserver);
                  return;
              }
              activeStateChanged(shouldBeActive());
          }
      
          @Override
          boolean isAttachedTo(LifecycleOwner owner) {
              return mOwner == owner;
          }
      
          @Override
          void detachObserver() {
              mOwner.getLifecycle().removeObserver(this);
          }
      }
      
      //抽象类
      private abstract class ObserverWrapper {
              final Observer<T> mObserver;
              boolean mActive;
              int mLastVersion = START_VERSION;
      
              ObserverWrapper(Observer<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;
                  if (wasInactive && mActive) {
                      onActive();
                  }
                  if (LiveData.this.mActiveCount == 0 && !mActive) {
                      onInactive();
                  }
                  if (mActive) {
                      dispatchingValue(this);
                  }
              }
          }
      
      //接口
      public interface GenericLifecycleObserver extends LifecycleObserver {
          /**
           * Called when a state transition event happens.
           *
           * @param source The source of the event
           * @param event The event
           */
          void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
      }
      
    • 通过上面的代码可以发现什么?
      • GenericLifecycleObserver是一个接口,ObserverWrapper是一个抽象类,而LifecycleBoundObserver则是ObserverWrapper的子类,并且重写了其中几个方法;
      • 在LifecycleBoundObserver的shouldBeActive()方法,在 owner 处于至少是 STARTED 的状态下认为是 active 状态;
      • 而且它也实现了 GenericLifecycleObserver 接口,可以监听 lifecycle 回调。在 onStateChanged() 方法里处理了生命周期改变的事件,在这个方法中,当接收到 DESTROYED 的事件会自动解除跟 owner 的绑定;
      • 将下个流程交给了 activeStateChanged(),这里具体可以看抽象类ObserverWrapper中的activeStateChanged源码;
    • 看一下ObserverWrapper抽象类中activeStateChanged方法中,onActive和onInactive分别干什么呢?
      • 对于onActive方法,当活动观察者的数量从0变为1时调用;对于onInactive方法,当活动观察者的数量从1变为0时调用
      if (wasInactive && mActive) {
          onActive();
      }
      if (LiveData.this.mActiveCount == 0 && !mActive) {
          onInactive();
      }
      
    • 看一下ObserverWrapper抽象类中activeStateChanged方法中,dispatchingValue是干什么呢?
      • 这个方法在分析下面setValue源码时还会说到,具体看下面的介绍!

    7.3 看看mObservers.putIfAbsent操作

    • 关于observe源码中这一行代码ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper)作用是什么呢?
      • mObservers.putIfAbsent(observer, wrapper)存入容器中,mObservers.putIfAbsent这个添加数据的方式比较少见。
      • 看了下面源代码可知,支持键值对存储,用链表实现,不是线程安全的。既然这里有存数据,那肯定有地方会取数据用到,这个后面会说到……
      //mObservers是一个集合
      private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers =
                  new SafeIterableMap<>();
      
      //在SafeIterableMap类中的putIfAbsent方法
      public V putIfAbsent(@NonNull K key, @NonNull V v) {
          Entry<K, V> entry = get(key);
          if (entry != null) {
              return entry.mValue;
          }
          put(key, v);
          return null;
      }
      
      protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
          Entry<K, V> newEntry = new Entry<>(key, v);
          mSize++;
          if (mEnd == null) {
              mStart = newEntry;
              mEnd = mStart;
              return newEntry;
          }
      
          mEnd.mNext = newEntry;
          newEntry.mPrevious = mEnd;
          mEnd = newEntry;
          return newEntry;
      
      }
      

    7.4 注册观察者流程

    • 那么注册观察者之后的触发流程是怎样的?
      • 调用 observe() 注册后,由于绑定了 owner,所以在 active 的情况下,使用LiveData中setValue发送数据,则 Observer 会立马接受到该数据修改的通知。
      • observe ——> onStateChanged ——> activeStateChanged ——> dispatchingValue ——> considerNotify ——> onChanged
      • 至于最终走到了onChanged方法,这个方法则是交给外部开发者处理接收消息事件的逻辑

    08.setValue发送源码分析

    8.1 setValue源码分析

    • LiveData 更新数据方式有两个,一个是 setValue() 另一个是 postValue(),这两个方法的区别是,postValue() 在内部会抛到主线程去执行更新数据,因此适合在子线程中使用;而 setValue() 则是直接更新数据。
      @MainThread
      protected void setValue(T value) {
          assertMainThread("setValue");
          // 这里的 mVersion,它本问题关键,每次更新数据都会自增,默认值是 -1。
          mVersion++;
          mData = value;
          dispatchingValue(null);
      }
      
    • 跟进下 dispatchingValue() 方法,注意,这里需要重点看considerNotify代码:
      private void dispatchingValue(@Nullable ObserverWrapper initiator) {
          // mDispatchingValue的判断主要是为了解决并发调用dispatchingValue的情况
          // 当对应数据的观察者在执行的过程中, 如有新的数据变更, 则不会再次通知到观察者。所以观察者内的执行不应进行耗时工作
          if (mDispatchingValue) {
              //给分发失败打个标记
              mDispatchInvalidated = true;
              return;
          }
          // 标记分发开始
          mDispatchingValue = true;
          do {
              mDispatchInvalidated = false;
              //这里需要注意:区分ObserverWrapper对象为空,和不为空的逻辑是不一样的
              if (initiator != null) {
                  // 等下重点看这里的代码
                  considerNotify(initiator);
                  initiator = null;
              } else {
                  //可以发现这里用到mObservers集合,使用迭代器遍历数据
                  for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                          mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                      // 等下重点看这里的代码
                      considerNotify(iterator.next().getValue());
                      if (mDispatchInvalidated) {
                          break;
                      }
                  }
              }
          } while (mDispatchInvalidated);
          // 标记分发开始
          mDispatchingValue = false;
      }
      
    • 接下来看一下上面源码中initiator对象为空判断逻辑区别
      • dispatchingValue 这里分两种情况:ObserverWrapper不为null和ObserverWrapper为null
      • ObserverWrapper不为null 的情况。LifecycleBoundObserver.onStateChanged 方法里调用了 activeStateChanged ,而该方法调用dispatchingValue(this);传入了 this ,也就是 LifecycleBoundObserver ,这时候不为 null 。也就是说生命周期改变触发的流程就是这种情况,这种情况下,只会通知跟该 Owner 绑定的 Observer。
      • ObserverWrapper为null 的情况。经过分析发现在setValue方法中调用dispatchingValue(null)传递了空对象,这个时候的流程则会通知 active 的mObservers

    8.2 看一下considerNotify()做什么

    • 然后看一下considerNotify() 方法做了什么,代码如下所示,这里有道词典翻译下注释
      • 如果ObserverWrapper的mLastVersion小于LiveData的mVersion,就会去回调mObserver的onChanged方法。
      • 每个新的订阅者,其version都是-1,LiveData一旦设置过其version是大于-1的(每次LiveData设置值都会使其version加1),这样就会导致LiveDataBus每注册一个新的订阅者,这个订阅者立刻会收到一个回调,即使这个设置的动作发生在订阅之前。
      private void considerNotify(ObserverWrapper observer) {
          if (!observer.mActive) {
              return;
          }
          // 检查最新的状态b4调度。也许它改变了状态,但我们还没有得到事件。
          // 我们还是先检查观察者。活动,以保持它作为活动的入口。
          // 因此,即使观察者移动到一个活动状态,如果我们没有收到那个事件,我们最好不要通知一个更可预测的通知顺序。
          if (!observer.shouldBeActive()) {
              observer.activeStateChanged(false);
              return;
          }
          
          //注意认真看下面的代码
          if (observer.mLastVersion >= mVersion) {
              return;
          }
          observer.mLastVersion = mVersion;
          //noinspection unchecked
          observer.mObserver.onChanged((T) mData);
      }
      
    • 思考一下dispatchingValue除了setValue会调用,其他还有地方调用么?
      • dispatchingValue除了在我们主动更新数据的时候会触发,
      • 当LifeCircleOwner的状态发生变化的时候,会调用LiveData.ObserverWrapper的activeStateChanged函数。
      • 在我们的观察者状态变更(inactive->active)的时候, 也会通知到, 这就导致了LiveData必然支持粘性事件。
      • 如果这个时候ObserverWrapper的状态是active,就会调用LiveData的dispatchingValue。
      • 它主要是处理分发通知逻辑,并且在分发通知前会判断 owner 的状态,再加上 LiveData 本身内部的版本管理,确保了只会发送最新的数据给 active 状态下的 Observer。
      • LiveData 对同时多次修改数据做了处理,如果同时多次修改,只会修改为最新的数据。
      private abstract class ObserverWrapper {
          final Observer<T> mObserver;
          boolean mActive;
          int mLastVersion = START_VERSION;
          //省略部分代码
          void activeStateChanged(boolean newActive) {
              if (newActive == mActive) {
                  return;
              }
              // 当observer的状态从active->inactive, 或者inactive->active的时候走以下流程
              // 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();
              }
              //当observer是从inactive->active的时候,需要通知到观察者
              if (mActive) {
                  dispatchingValue(this);
              }
          }
      }
      

    8.3 发送消息事件流程

    • 那么发送消息事件之后的触发流程是怎样的?
      • setValue ——> dispatchingValue(null) ——> considerNotify(注意,这里是个for迭代器循环,表示通知所有观察者) ——> onChanged

    09.observeForever源码

    • 这个方法是干什么用的呢?看一下源代码
      • 将给定的观察者添加到观察者列表中,意味着给定的观察者将接收所有事件,并且永远不会被自动删除,不管在什么状态下都能接收到数据的更改通知
      @MainThread
      public void observeForever(@NonNull Observer<T> observer) {
          // 创建一个AlwaysActiveObserver对象
          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);
      }
      

    10.LiveData源码总结

    • LiveData的观察者可以联动生命周期, 也可以不联动。在联动生命周期时,会自动在 DESTROYED 的状态下移除 Observer ,取消订阅,所以不用担心内存泄露;
    • LiveData的观察者只能与一个LifecycleOwner绑定, 否则会抛出异常。而一个 owner 可以绑定多个 Observer 实例;
    • LiveData 跟 LifecycleOwner 绑定,能感知生命周期变化,并且只会在 LifecycleOwner 处于 Active 状态(STARTED/RESUMED)下通知数据改变;如果数据改变发生在非 active 状态,数据会变化,但是不发送通知,等 owner 回到 active 的状态下,再发送通知;
    • 使用observeForever()方法,会注意AlwaysActiveObserver对象,意味着给定的观察者将接收所有事件,并且永远不会被自动删除,不管在什么状态下都能接收到数据的更改通知
    • LiveData 利用版本管理、绑定 Lifecycle 确保了只会发送最新的数据给 active 状态下的 Observer
    • image
    • image

    参考博客

    开源LiveData事件总线:https://github.com/yangchong211/YCLiveDataBus

    相关文章

      网友评论

        本文标题:LiveData详细分析

        本文链接:https://www.haomeiwen.com/subject/ldkhrhtx.html