关于LiveData 的源码分析

前言

在 Lifecycle-aware Components 源码分析 一文中,我们已经分析了 Lifecycle 框架中所有的 lifecyle 事件产生流程以及分发流程。本文将会基于这部分知识来分析 Lifecycle 框架中的 LiveData 组件。

提出问题

结合 LiveData javadoc, LiveData 文档,我们可以了解到 LiveData 主要作用是数据发生变化时通知 Observer,那么 LiveData 是如何实现这部分内容的呢?

LiveData

observe

有监听得先有注册,先来看 observe 方法:

@MainThread

public void observe(LifecycleOwner owner, Observer<T> observer) {

  if (owner.getLifecycle().getCurrentState() == DESTROYED) {

      // ignore

      return;

  }

  LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

  LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);

  if (existing != null && existing.owner != wrapper.owner) {

      throw new IllegalArgumentException("Cannot add the same observer"

              + " with different lifecycles");

  }

  if (existing != null) {

      return;

  }

  owner.getLifecycle().addObserver(wrapper);

  wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));

}

observe 方法需运行在主线程中,执行时会将 Observer 传入 LifecycleBoundObserver,并将 LifecycleBoundObserver 通过 addObserver 注册至 Lifecycle,紧接着调用了 LifecycleBoundObserver 的 activeStateChanged 方法。

LifecycleBoundObserver

接着看 LifecycleBoundObserver:

class LifecycleBoundObserver implements LifecycleObserver {

  public final LifecycleOwner owner;

  public final Observer<T> observer;

  public boolean active;

  public int lastVersion = START_VERSION;

  LifecycleBoundObserver(LifecycleOwner owner, Observer<T> observer) {

      this.owner = owner;

      this.observer = observer;

  }

  @SuppressWarnings("unused")

  @OnLifecycleEvent(Lifecycle.Event.ON_ANY)

  void onStateChange() {

      if (owner.getLifecycle().getCurrentState() == DESTROYED) {

          removeObserver(observer);

          return;

      }

      // immediately set active state, so we'd never dispatch anything to inactive

      // owner

      activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));

  }

  void activeStateChanged(boolean newActive) {

      if (newActive == active) {

          return;

      }

      active = newActive;

      boolean wasInactive = LiveData.this.mActiveCount == 0;

      LiveData.this.mActiveCount += active ? 1 : -1;

      if (wasInactive && active) {

          onActive();

      }

      if (LiveData.this.mActiveCount == 0 && !active) {

          onInactive();

      }

      if (active) {

          dispatchingValue(this);

      }

  }

}

static boolean isActiveState(State state) {

  return state.isAtLeast(STARTED);

}

不难看出 onStateChange 会接收所有的 lifecycle 事件。当 LifecycleOwner 的状态处于 STARTED 或 RESUMED 时,传入 activeStateChanged 的值为 true,即 LifecycleBoundObserver 会被标记为激活状态,同时会增加 LiveData 的 mActiveCount 计数。接着可以看到,onActive 会在 mActiveCount 为 1 时触发,onInactive 方法则只会在 mActiveCount 为 0 时触发。这里就与 LiveData javadoc 所描述的完全吻合(In addition, LiveData has onActive() and onInactive() methods to get notified when number of active Observers change between 0 and 1. This allows LiveData to release any heavy resources when it does not have any Observers that are actively observing.)。

dispatchingValue

此后,如果 LifecycleBoundObserver 处于激活状态,则会调用 dispatchingValue:

private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {

  if (mDispatchingValue) {

      mDispatchInvalidated = true;

      return;

  }

  mDispatchingValue = true;

  do {

      mDispatchInvalidated = false;

      if (initiator != null) {

          considerNotify(initiator);

          initiator = null;

      } else {

          for (Iterator<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =

                  mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {

              considerNotify(iterator.next().getValue());

              if (mDispatchInvalidated) {

                  break;

              }

          }

      }

  } while (mDispatchInvalidated);

  mDispatchingValue = false;

}

其中 mDispatchingValue, mDispatchInvalidated 只在 dispatchingValue 方法中使用,显然这两个变量是为了防止重复分发相同的内容。

considerNotify

接下来,无论哪个路径都会调用 considerNotify:

private void considerNotify(LifecycleBoundObserver observer) {

  if (!observer.active) {

      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 (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {

      return;

  }

  if (observer.lastVersion >= mVersion) {

      // 数据已经是最新

      return;

  }

  observer.lastVersion = mVersion;

  //noinspection unchecked

  observer.observer.onChanged((T) mData);

}

注:mVersion 代表的是数据变化的次数,下文会补充说明。

显然 considerNotify 的作用就是通知处于激活状态且数据未更新的 Observer 数据已发生变化。

其中 mData 即是 LiveData 当前的数据,默认是一个全局 Object:

private static final Object NOT_SET = new Object();

private Object mData = NOT_SET;

可能会有人担心当 LiveData 的 mData 未发生变更时,第一次调用 observe 会将 NOT_SET 传递到 Observer 中。事实上并不会,因为 LiveData 的 mVersion 和 LifecycleBoundObserver 的 lastVersion 的默认值均为 START_VERSION:

public abstract class LiveData<T> {

    ...

    static final int START_VERSION = -1;

    private int mVersion = START_VERSION;

    ...

    class LifecycleBoundObserver implements LifecycleObserver {

        ...

        public int lastVersion = START_VERSION;

        ...

    }

    ...

}

在 observer.lastVersion >= mVersion 判断时就会直接返回而不执行 observer.observer.onChanged((T) mData)。

setValue

再来看 setValue:

@MainThread

protected void setValue(T value) {

  assertMainThread("setValue");

  mVersion++;

  mData = value;

  dispatchingValue(null);

}

setValue 与 observe 方法一样均需要在主线程上执行,当 setValue 的时候 mVersion 的值会自增,并通知 Observer 数据发生变化。

postValue

setValue 还有另一个替代的方法 postValue:

protected void postValue(T value) {

  boolean postTask;

  synchronized (mDataLock) {

      postTask = mPendingData == NOT_SET;

      mPendingData = value;

  }

  if (!postTask) {

      return;

  }

  AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

}

private final Runnable mPostValueRunnable = new Runnable() {

  @Override

  public void run() {

      Object newValue;

      synchronized (mDataLock) {

          newValue = mPendingData;

          mPendingData = NOT_SET;

      }

      //noinspection unchecked

      setValue((T) newValue);

  }

};

其中 AppToolkitTaskExecutor 是通过一个以 Main Looper 作为 Looper 的 Handler 将 mPostValueRunnable 运行在主线程上,所以 postValue 可以运行在任意线程上,而 Observer 的 OnChange 回调会执行在主线程上。

observeForever

最后再看下 observeForever

@MainThread

public void observeForever(Observer<T> observer) {

  observe(ALWAYS_ON, observer);

}

private static final LifecycleOwner ALWAYS_ON = new LifecycleOwner() {

  private LifecycleRegistry mRegistry = init();

  private LifecycleRegistry init() {

      LifecycleRegistry registry = new LifecycleRegistry(this);

      registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

      registry.handleLifecycleEvent(Lifecycle.Event.ON_START);

      registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);

      return registry;

  }

  @Override

  public Lifecycle getLifecycle() {

      return mRegistry;

  }

};

可以看到,observeForever 将 Observer 注册了在一个永远处于 RESUMED 的 LifecycleOwner 中,所以通过 observeForever 注册的 Observer 需要通过 removeObserver 来取消数据变化的监听。

总结

至此,我们已经明白 LiveData 主要是通过 LifecycleBoundObserver 与 Lifecycle 结合来控制数据的分发。

LiveData 的代码比 Lifecycle 要简单得多,主要是有了 Lifecycle 部分的分析作为基础,看起来很轻松。

附《Android核心知识笔记2020》分享

前段时间我和圈子里的几位架构师朋友一起闲聊时的突发奇想,我们在学习Android开发的时候或多或少也受到了一些前辈的指导,所以想把这份情怀延续下去。三个月后,这套资料就出来了,需要这份资料的朋友加Android学习交流群1049273031即可获取。

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

推荐阅读更多精彩内容