LiveData源码解析

掘金文章链接

基于:
macOs:10.14/AS:3.4/Android build-tools:28.0.0

思路

看源码前先考虑下如果要自己实现 LiveData 应该怎么做?

基本做法:

  1. 目标数据私有;
  2. 开放 setter 方法用于更新目标数据;
  3. 提供方法添加数据变化监听器(Observer);

扩展:

  1. 允许子线程更新数据, 因此 setter 需要考虑同步;
  2. 项目中可能多个地方需要用到目标数据,因此回调监听器(Observer)需支持添加多个;
  3. 遍历通知各 Observer 更新数据期间若数据发生了变化,要如何处理;
  4. 数据变化时常常都需要更新UI,而UI有生命周期,因此 Observer 需要提供 Lifecycle 相关逻辑支持,包括:
    1. 定义处于哪些生命周期的 Observer 可以收到数据更新;
    2. onDestroy() 时自动移除 Observer 等;
  5. 如何定义 数据变化 呢? 最简单直接的做法是每次触发 setter 方法时都当作数据发生了变化, 遍历通知所有 Observer 即可, 更进一步的判定交给调用方;
    ......

简单使用

// 定义 livedata
object ParaConfig {
    // 定义一个私有的 `MutableLiveData`
    private val msgLiveData = MutableLiveData<String>()

    // 开放给外部获取数据更新时,提供不可变的 `LiveData` 即可;
    fun getMsgLiveData(): LiveData<String> = msgLiveData

    fun updateMsg(msg: String, inBgThread: Boolean = false) {
        if (inBgThread) {
            msgLiveData.postValue(msg) // 在子线程中更新数据
        } else {
            msgLiveData.value = msg // 在主线程中更新数据
        }
    }
}
// 添加 `Observer`
class LiveDataFrag : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // 添加一个跟生命周期相关的 `Observer`
        ParaConfig.getMsgLiveData().observe(this, Observer<String> { newMsg ->
            tv_msg.text = newMsg
        })

        // 无视生命周期, 每次数据变化时都会回调,需要自行移除observer
        ParaConfig.getMsgLiveData().observeForever {
            Logger.d("observeForever: $it","tag_livedata")
        }
    }
}

看源码我还是习惯从调用入口一步步往下看, 以下也是按照这种顺序来;

实现

livedata

添加 Observer

// LiveData.java
public abstract class LiveData<T> {
    private static final Object NOT_SET = new Object();
    // 实际数据,类型为 Object 而非 T
    private volatile Object mData = NOT_SET;
    // 存储所有的 Observer
    private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

    // 添加跟生命周期相关的 observer
    // 目标数据
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        // 若 LifecycleOwner 已处于已被销毁,则忽略该 observer
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }

        // 将 LifecycleOwner 和 Observer 功能进行绑定包装
        // 生成支持生命周期感知的 Observer: LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 避免重复添加相同的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;
        }

        // 实现对 LifecycleOwner 生命周期的感知
        // 关键还是 LifecycleBoundObserver 类,我们马上进去看一下
        owner.getLifecycle().addObserver(wrapper);
    }

    // 无视生命周期, 每次数据发生变化时,都会回调通知 Observer
    // 需要手动在不需要时移除 Observer
    @MainThread
    public void observeForever(@NonNull Observer<T> observer) {
        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);
    }
}

MutableLiveData 只是简单重写了 LiveDatasetValue(T)/postValue(T) 方法, 改为 public 而已;

数据如何传递的: setValue(T) 解析

// LiveData.java
@MainThread
protected void setValue(T value) {
    // 只能在UI线程中调用,否则抛出异常,崩溃
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

private boolean mDispatchingValue;

// 若参数 initiator 非空,则表示只通知特定的 ObserverWrapper, 否则是回调通知所有 ObserverWrapper
// 由于只在主线程中调用,因此不用做多线程处理
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 小技巧: 在遍历通知各 ObserverWrapper 期间, 若数据发生了变化, 则会重新遍历通知
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }

    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {// initiator 非空时,只更新特定 ObserverWrapper
            considerNotify(initiator); // 实际更新数据的方法
            initiator = null;
        } else { // 否则遍历更新所有 ObserverWrapper
            for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                // 若数据发生变化, 则退出for循环
                // 而外层 do...while() 判定条件为true,就会重新遍历通知各 ObserverWrapper;
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

// 判断是否要将数据分发到指定的 ObserverWrapper
private void considerNotify(ObserverWrapper observer) {
    // 是否可以分发数据到指定的 observer, 由 mActive 来控制
    // 所以 mActive 很重要,具体下一节解读
    if (!observer.mActive) {
        return;
    }

    // 二次确认状态, 可能生命周期发生了变化,但 mActive 并未改变
    if (!observer.shouldBeActive()) {
        // active -> inactive 时通知更新状态
        // inactive 状态下就不需要分发数据了
        observer.activeStateChanged(false);
        return;
    }

    // 若 ObserverWrapper 持有的数据值已是最新版本, 自然也不用分发
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;

    // 通知 observer 数据有更新
    // observer.mObserver 是调用方实际传入的
    observer.mObserver.onChanged((T) mData);
}

用于子线程调用的 postValue(T) 会发射一个 Runnable 到主线程中, 最终也是通过 setValue(T) 来实现数据分发;
当然, postValue(T) 也可以在主线程调用,不过是多此一举,如:

// observer会先收到 "msgFromSetValue" 然后才收到 "msgFromPostValue"
someBtnView.setOnClickListener {
    msgLiveData.postValue("msgFromPostValue")
    msgLiveData.value = "msgFromSetValue"
}

ObserverWrapper 类解析

ObserverWrapper
// LiveData 的内部抽象类
// 包装用户传入的 Observer, 提供数据版本记录以及active状态(生命周期)判断
private abstract class ObserverWrapper {
    final Observer<T> mObserver;
    boolean mActive; // 确定当前 ObserverWrapper 是否生效,true时才可进行数据更新
    int mLastVersion = START_VERSION; // 当前持有的数据版本号,初始值为 -1

    ObserverWrapper(Observer<T> observer) {
        mObserver = observer;
    }

    // 判断该 Observer 是否有效, true 时才会触发 activeStateChanged()
    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    // 更新本 ObserverWrapper 的状态
    void activeStateChanged(boolean newActive) {
        // 若状态没变化,不需要更新,直接返回
        if (newActive == mActive) {
            return;
        }

        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;

        // 处于 active 状态的 observer 数量从0 -> 1时,触发 onActive() 方法
        if (wasInactive && mActive) {
            onActive();
        }

        // 处于 active 状态的 observer 数量从 1 -> 0时,触发 onInactive() 方法
        // 提供给观察者释放资源的机会
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }

        // observer 从  inactive -> active 时, 更新数据
        if (mActive) {
            // 将数据发送给该 observer
            dispatchingValue(this);
        }
    }
}

此类并未给出 inactive/active 具体是何种状态, 具体应是由 shouldBeActive() 来确定, 因此需要从子类查找;

子类 AlwaysActiveObserver比较简单, 只是将shouldBeActive() 固定返回 true,表示一直生效, 每次数据发生变化时都需要发送通知;
我们看下 LifecycleBoundObserver 类;

LifecycleBoundObserver 解析

// LiveData 内部类
// 将 LifecycleObserver 和 ObserverWrapper 结合,当生命周期变化时,通知 ObserverWrapper 更新数据
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull final LifecycleOwner mOwner;

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

    @Override
    boolean shouldBeActive() {
        // 此处定义了哪些生命周期是 `active` 的
        // 结合 Lifecycle.State 类 ,我们知道是: STARTED/RESUMED 两种状态
        // 对应于生命周期 `onStart()` 之后到 `onStop()` 之前
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    // 生命周期变化时回调本方法
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        // 若当前 LifecycleOwner onDestory() 了, 则自动移除 observer, 避免内存泄露
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        // 将 shouldBeActive() 返回的状态当做本 ObserverWrapper 的状态
        // 即  mActive = shouldBeActive()
        activeStateChanged(shouldBeActive());
    }

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

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

小结

  1. 只能在主线程中进行 Observer 的添加:
    1. observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
    2. observeForever(@NonNull Observer<T> observer)
  2. 添加带 LifecycleOwnerObserver 时, 若发生 onDestory() ,则会自动移除 Observer;
  3. 数据只会在 LifecycleOwner 处于 onStart()/onResume()/onPause() 生命周期时,才会分发;
  4. 若处于 active 的 Observer 数量从 1 -> 0, 回调 onInactive() ,适用于子类进行资源释放;
  5. 若处于 active 的 Observer 数量从 0 -> 1, 回调 onActive();
  6. LiveData 类和 ObserverWrapper 类都会在内部持有一个数据版本号;
  7. LiveData 数据发生变化时,会切换到主线程,然后遍历所有 Observer, 并将数据分发给处于 active 状态并且数据版本号不一致的 Observer;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342