Android LiveData 浅析

249 阅读7分钟

什么是LiveData

官网中是这么定义的:LiveData 是一种可观察的数据存储器类.具有生命周期感知能力

如何理解 LiveData 具有生命周期感知能力

当界面处于可见(激活状态)时候才能收到数据的变化

举个简单的例子,两个界面,MainAct 和 SecondAct 共同处理一个 LiveData

界面如下

MainActSecondAct

通过打印能够看到

2020-09-17 20:12:35.877 I: main Act data 1
2020-09-17 20:12:36.828 I: main Act data 2
2020-09-17 20:12:37.505 I: main Act data 3
2020-09-17 20:12:38.920 I: Main Act 跳转 Second Act
2020-09-17 20:12:38.993 I: second Act data 3
2020-09-17 20:12:44.384 I: second Act data 4
2020-09-17 20:12:44.977 I: second Act data 5
2020-09-17 20:12:45.360 I: second Act data 6
2020-09-17 20:12:45.570 I: second Act data 7
2020-09-17 20:12:47.864 I: second Act finish
2020-09-17 20:12:47.948 I: main Act data 7

  • 当我们点击到3的时候 跳转到 SecondAct 界面 立马触发了 livedata 将 在SecondAct 的状态改成3
  • 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化
  • 当回退到MainAct 的时候 立马触发了MainAct 的 livedata 变化 并且只会显示最新的状态

liveData 是如何工作的

基于上面的小示例,我们能够大概猜测到,MainAct 和 SecondAct 两个界面都注册了观察者,被livedata 保存了起来,当点击+1 的时候,在遍历所有的观察者,通知其状态发生了变化,

首先 livedata 有一个观察者,观察状态变化的,内部呢,也有一个观察者,通过lifecycle 观察界面的生命周期变化

//LiveData

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //判断是否是主线程
    assertMainThread("observe");
    // 如果当前的 lifecycle 已经GG了 就不管了
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //创建一个 lifecycle 的观察者
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //保存在 mObservers map 当中
    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);
}

LiveData 会将所有的观察者添加到Map 中保存

当我们+1 的时候

//LiveData
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    //Version 累加
    mVersion++;
    //记录当前最新的 data
    mData = value;
    dispatchingValue(null);
}
//LiveData
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    //省略代码
    do {
        //省略代码
        if (initiator != null) {
            considerNotify(initiator);
        } else {
            //遍历所有的状态观察者
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                //通知改变
                considerNotify(iterator.next().getValue());
            }
        }
    } while (mDispatchInvalidated);
}
//LiveData
private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }

        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //默认是 -1   上面在我们setValue 的时候 Version +1 所以当前的 Version ==0
        // -1 >= 0  不满足 
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //记录当前的 version  == 0 
        observer.mLastVersion = mVersion;
        // 传递 数据变化
        observer.mObserver.onChanged((T) mData);
}

就这样我们完成了一次状态的变化

当setValue 时候,会遍历所有的状态观察者 并通知数据变化

livedata 如何处理未激活的观察者不接受变化的数据

还是上面的小例子, 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化

在上面分析LiveData 如何通知发送数据变化的时候,有下面的方法,这方法有一个细节,判断了是否是在激活状态,如果不是激活状态就不执行change

//LiveData
private void considerNotify(ObserverWrapper observer) {
    //在这里判断当前的观察者是否属于激活状态
    if (!observer.mActive) {
        return;
    }
   
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;

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

跟着这个状态寻找,可以看到 livedata 是 通过 LifeCycle 接受观察者的状态的

//LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    //这里是 监听界面变化的 观察者
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        //当界面生命周期发生变化的时候 调用下面的方法
        activeStateChanged(shouldBeActive());
    }
}

而这个LifeCycle在添加观察者的时候就已经被LifeCycle 添加到自己的观察者中

在我们调用 observe方法的时候 创建了 LifecycleBoundObserver

//LiveData
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //创建了一个 LifecycleBoundObserver
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //通过LifeCycle 添加 
    owner.getLifecycle().addObserver(wrapper);
}

详细看一下这方法,判断如果状态不相同,就修改状态,而这个仅仅是对于 调用了 observe 方法的 observer 才生效,每一个 observer 维护这自己的 状态

这里当刚刚被激活的时候,newActive == true, 当前的 mActiveCount == 0, 然后执行 +1 的操作 得到 mActiveCount == 1,下面的逻辑判断 因为 wasInactive 和 mActive 都是 true, 通知被激活了,执行 onActive

再往下 发现 mActiveCount ==1 所以不执行 onInactive 方法

//LiveData / ObserverWrapper
void activeStateChanged(boolean newActive) {
        //当状态相同的时候 不会触发
        if (newActive == mActive) {
            return;
        }
        //修改 observer 当前LiveData 的状态 
        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        if (wasInactive && mActive) {
            //通知 observer  livedata 数据被激活
            onActive();
        }
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            //通知observer LiveData 数据处于不活跃状态
            onInactive();
        }
        if (mActive) {
            dispatchingValue(this);
        }
    }

补充一下,因为这里会执行多次,所以放上一个 手写的时序图

能够知道,其实正在改变状态的是在 onStart 和 onStop

到这里 我们知道了 为什么 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化 的原因。

LiveData 通过观察者内部自己维护的状态进行判断,是否处于激活状态,而这些状态则是通过LifeCycle 进行触发

当界面激活的时候,livedata 如何将最新的数据发给观察者

在上面的 解释 我们知道,如果MainAct 重新 onStart 那么 observer 所维护的 激活状态就被打开

//LiveData / ObserverWrapper
void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        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
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    //省略代码
    do {
        //省略代码
        if (initiator != null) {
            considerNotify(initiator);
        } else {
            //遍历所有的状态观察者
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                //通知改变
                considerNotify(iterator.next().getValue());
            }
        }
    } while (mDispatchInvalidated);
}

在这里的时候,想象一下,MainAct 因为没被激活,所以 他所维护的 observer 记录的 version 还是 之前 的 version 而 真正的version 因为在 SecondAct 一直被++ 所以远大于 Main 记录的值。 当MainAct onStart 以后,会立马重新判断,这个时候 状态已经改成被激活了,并且 observer 记录的version < 真正的Version 所以会执行一次changed

//LiveData
private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            //未被激活 执行这里
            return;
        }

        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        // mainAct记录的  <  当前记录的值
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 传递 数据变化  最终执行到这里
        observer.mObserver.onChanged((T) mData);
}

LiveData 通过LifeCycle 得知自己 被激活,然后通过记录的Version 判断是否需要重新changed

LiveData 不建议当做Event 使用

还是之前的示例,当回到FirstAct 的时候,livedata 依然能够收到事件,作为事件总线,这种是不被允许的,不过有大佬做了一个 LiveDataBus 能够替换掉EventBus

onActive 和 onInactive

在上面说明了,对于LiveData 本身而言,是无意义的,是告诉开发者 您当前的Observer 所观察的 LiveData 是否被激活

observeForever

这个方法和 observe 最大的区别在源码中可以看到

observe。创建的是一个 LifecycleBoundObserver ,他的判断条件根据lifecycle 判断

//LifecycleBoundObserver
@Override
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

当界面onDestory 的时候

//LifecycleBoundObserver
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        //remove了
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

observeForever 创建的是一个 AlwaysActiveObserver,则直接返回为true

//AlwaysActiveObserver
@Override
boolean shouldBeActive() {
    return true;
}

因为不在具有生命感知能力,就需要手动去自己remove,并且 即使mainAct 界面处于未被激活的状态 也依然可以收到

那么他是如何处理即使在未被激活的界面 依然能够触发变化呢

//LiveData
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    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);
}

observeForever 需要开发者手动去 remove 而observe 则是由LiveData 自行remove