前言
Android Jetpack 常用组件 Lifecycle、ViewModel、LiveData 原理分析。
基石 Lifecycle
首先可以总体看一下涉及到 Lifecycle 组件的主要类,下面就其中的细节慢慢展开。
Lifecycle 有什么用?
Lifecycle 是具备宿主生命周期感知能力的组件。它能持有组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他观察者监听宿主的状态。它也是 Jetpack 组件库的的核心基础,LiveData , ViewModel 组件等也都是基于它来实现的。
Lifecycle 怎么用?
其实关于 Lifecycle 怎么用本质上是在说,我们改如何实现 addObserver() 中的这个 observer .
kotlin
lifecycle.addObserver(EasyObserver())
从上面的概览图出发,结合 LifecycleObserver 及其子类,实现一个 Lifecycle 的观察者可以有三种方式。
kotlin
class EasyObserver : LifecycleObserver,DefaultLifecycleObserver, LifecycleEventObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun foo() {}
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
Log.d(LIFECYCLE_TAG, "onCreate() called with: owner = $owner")
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
val value = owner.lifecycle.currentState
Log.d(LIFECYCLE_TAG, "onResume() called onResume, currentState =$value")
if (value.isAtLeast(Lifecycle.State.STARTED)) {
Log.d(LIFECYCLE_TAG, "atLeast started")
}
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
Log.d(LIFECYCLE_TAG, "onPause() called with: owner = $owner")
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
Log.d(LIFECYCLE_TAG, "onStateChanged() called with: source = $source, event = $event")
}
}
- 直接实现 LifecycleObserver 接口,给自定义方法添加 OnLifecycleEvent 注解,在相应的生命周期方法触发方法调用。
- 直接实现 DefaultLifecycleObserver 接口, 覆写生命周期方法
- 直接实现 LifecycleEventObserver 接口,在其 onStateChanged 方法中按参数实现对应生命周期的功能。
记得一定要在实现了 LifecycleOwner 的组件中注册这个 LifecycleObserver ,否则谁来给他分发生命周期呢?
Activity/Fragment 是如何实现 Lifecycle 的 ?
关于如何实现 Lifecycle ,我们可以从被观察者和观察者两侧分别展开分析。
被观察的宿主
首先是被观察者,也就是实现了 LifecycleOwner 接口,表示自己是可以被观察的宿主的类。在这一点上Activity 和 Fragment 本质上是相似的,都是通过借助组件自身的生命周期(Activity 早期版本依赖 ReportFragment) ,通过 LifecycleRegistry 对所有的观察者进行生命周期的分发。
java
public class ComponentActivity extends Activity implements LifecycleOwner{
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
protected void onCreate(Bundle bundle) {
super.onCreate(savedInstanceState);
//往Activity上添加一个fragment,用以报告生命周期的变化
//目的是为了兼顾不是继承自AppCompactActivity的场景.
ReportFragment.injectIfNeededIn(this);
}
这里的实现其实跟 Fragment 中的源码是一样的,在各个生命周期方法内利用 LifecycleRegistry 派发相应的 Lifecycle.Event 事件给每个观察者
java
public class ReportFragment extends Fragment{
public static void injectIfNeededIn(Activity activity) {
android.app.FragmentManager manager = activity.getFragmentManager();
if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
manager.executePendingTransactions();
}
}
@Override
public void onStart() {
super.onStart();
dispatch(Lifecycle.Event.ON_START);
}
@Override
public void onResume() {
super.onResume();
dispatch(Lifecycle.Event.ON_RESUME);
}
@Override
public void onPause() {
super.onPause();
dispatch(Lifecycle.Event.ON_PAUSE);
}
@Override
public void onDestroy() {
super.onDestroy();
dispatch(Lifecycle.Event.ON_DESTROY);
}
private void dispatch(Lifecycle.Event event) {
Lifecycle lifecycle = activity.getLifecycle();
if (lifecycle instanceof LifecycleRegistry) {
((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
}
}
LifecycleRegistry 在分发事件的时候会涉及到两个概念:
-
宿主生命周期 :就是我们烂熟于心的
oncreate,onstart onresume onpause onstop
-
宿主的状态 :指宿主执行了上述方法后,它处于何种生命状态了
这里其实可以类比线程的生命周期状态。注意到
- ON_CREATE 和 ON_STOP 这两个 event 都可以使 state 处于 CREATED;
- ON_START 和 ON_PAUSE 这两个 event 都可以使 state 处于 STARTED
这里比较微妙,可以多思考一下。我们可以看一下在 LifecycRegistry 中 handleLifecycleEvent
是如何处理的。
handleLifecycleEvent
java
public void handleLifecycleEvent(@NonNull Lifecycle.Event event){
//宿主的每个生命周期的变化都会分发一个对应的Lifecycle.Event,走到这里
//此时会根据需要分发的事件反推出 宿主当前的状态
State next = getStateAfter(event);
moveToState(next);
}
// moveToState方法只是将传入的宿主新的state和前持有宿主状态作比对,然后保存一下。
//如果宿主状态有变动,则调用sync方法来完成事件的分发和观察者状态的同步
private void sync() {
while (!isSynced()) {
//如果宿主当前转态 小于 mObserverMap集合中最先添加的那个观察者的状态
//则说明宿主可能发生了状态回退,比如当前是RESUMED状态,执行了onPause则回退到STARTED状态
//此时调用backwardPass把集合中的每个一观察者分发一个on_pause事件,并同步它的状态。
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner);
}
//如果宿主当前转态 大于 mObserverMap集合中最先添加的那个观察者的状态
//则说明宿主可能发生了状态前进,比如当前是STARTED状态,执行了onResume则前进到RESUMED状态
//此时调用forwardPass把集合中的每个一观察者分发一个on_resume事件,并同步它的状态。
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
}
说完了生命周期主动分发的场景,我们再来看看观察者注册的玄机.
addObserver
java
public void addObserver(@NonNull LifecycleObserver observer) {
//添加新的Observer时,会首先根据宿主的状态计算出它的初始状态,只要不是在onDestroy中注册的,它的初始状态都是INITIALIZED
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
//接着会把observer包装成ObserverWithState,这个类主要是包含了观察者及其状态。每个事件都会经由这个对象类转发,这个类后面会来分析
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
//添加到集合,如果之前已经添加过了,则return
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
return;
}
State targetState = calculateTargetState(observer);
//这里的while循环,是实现上图状态同步与事件分发的主要逻辑
//拿观察者的状态和宿主当前状态做比较,如果小于0,说明两者状态还没有对齐。
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
//接着就会分发一次相应的事件,于此同时statefulObserver的mState对象也会被升级
//假设是在宿主的onresume犯法内注册的该观察者
//第一次:分发on_Create事件,观察者状态INIT->CREATED
//第二次:分发on_Start事件,观察者状态CREATED->STARTED
//第三次:分发on_Resume事件,观察者状态STARTED->RESUMED
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
//再一次计算观察者应该到达的状态,在下一轮循环中和宿主状态在做比较,知道两者状态对齐,退出循环。
targetState = calculateTargetState(observer);
}
}
Lifecycle 的特性我们在任意生命周期方法内注册观察者都能接收到完成的生命周期事件,比如在onResume 中注册一个观察者,它会依次收到:
java
LifecycleEvent.onCreate -> LifecycleEvent.onStart -> LifecycleEvent.onResume
可以看到在 addObserver 中,会根据当将当前 oberver 和其所处的状态包装成一个 ObserverWithState .我们看一下为什么要这么做。
ObserverWithState
java
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = event.getTargetState();
mState = min(mState, newState);
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
这里有个细节可以注意一下,构造函数 observer 是 LifecycleObserver 类型的,而内部的 mLifecycleObserver 是 LifecycleEventObserver 类型的,是其子类。一开始我们说了,创建 observer 时可以有多种方式。 而到了这里,都会统一成 LifecycleEventObserver 这种实现进行处理。
观察者是如何实现统一的
至于 Lifecycling.lifecycleEventObserver 是如何将使用注解、实现 DefaultLifecycleObserver 等方式统一成 LifecycleEventObserver ,以及注解是如何生效的之类的内容,可以参考这篇"终于懂了"系列:Jetpack AAC完整解析,Lifecycle 完全掌握,分析的很详细了。
ProcessLifecycleOwner
使用ProcessLifecycleOwner可以直接获取应用前后台切换状态。其实内部实现就是统计 Activity 的状态,自己实现也是可以的。
java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//注册App生命周期观察者
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationLifecycleObserver());
}
/**
* Application生命周期观察,提供整个应用进程的生命周期
*
* Lifecycle.Event.ON_CREATE只会分发一次,Lifecycle.Event.ON_DESTROY不会被分发。
*
* 第一个Activity进入时,ProcessLifecycleOwner将分派Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME。
* 而Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP,将在最后一个Activit退出后后延迟分发。如果由于配置更改而销毁并重新创建活动,则此延迟足以保证ProcessLifecycleOwner不会发送任何事件。
*
* 作用:监听应用程序进入前台或后台
*/
private static class ApplicationLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForeground() {
Log.w(TAG, "ApplicationObserver: app moved to foreground");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackground() {
Log.w(TAG, "ApplicationObserver: app moved to background");
}
}
}
ViewModel
ViewModel 作为 Jetpack 常用的组件,最重要的原因就是其生命周期比 Activity、Fragment 长的这一点吧。
两点优势:
- 存储的数据只能当页面因为配置变更导致的销毁再重建时可复用
- 实现跨页面不同的(Activity)的数据共享,Application 内创建的 ViewModel ,同 Activity 多 Fragment 共享 ViewModel
回想我们创建 ViewModel 实例的代码
kotlin
val fooViewModel = ViewModelProvider(this).get(FooViewModel::class.java)
java
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
从图示和代码可看到,ViewModelProvider 内部是靠着 ViewModelStore 和 Factory 创建和管理内部的 ViewModel 实例。
java
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
因此,我们可以确定说,要在 Activity(Fragment) 销毁的时候保证 ViewModel 的存活,其实就是要保证 ViewModelStore 的存活,而 ViewModelStore 又是由 ViewModelStoreOwner 提供的,因此。问题就来到了 ViewModelStoreOwner 是如何维护 ViewModelStore 的。
可以看到 Activity 和 Fragment 都以不同的方式实现了 ViewModelStoreOwner。 Activity 是直接实现接口,而 Fragment 是通过代理实现。下面就来看看其中奥秘,为什么 Activity 实例重建的时候依旧可以保持之前的 ViewModelStore 可用。
Activity 如何维护 ViewModelStore
java
class ComponentActivity extends ViewModelStoreOwner{
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
public ViewModelStore getViewModelStore() {
if (mViewModelStore == null) {
//从源码上可以看出,会首先从`NonConfigurationInstances`来获取`ViewModelStore`实例对象,
//如果不为空那是不是就能做到复用了 ?
//所以重点在于`ViewModelStore`何时被存储到`NonConfigurationInstances`里面的.
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}
}
onRetainNonConfigurationInstance
因系统原因页面被回收时,会触发该方法,所以 viewModelStore 对象此时会被存储在 NonConfigurationInstance 中。在页面恢复重建时,会再次把这个 NonConfigurationInstance 对象传递到新的Activity 中实现对象复用。
java
class ComponentActivity{
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// 如果NonConfigurationInstance保存了viewModelStore,把它取出来
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
//把viewModelStore放到NonConfigurationInstances中并返回
nci.viewModelStore = viewModelStore;
//这样当页面被销毁时ViewModelStore就被保存起来了。
return nci;
}
}
注意这里的 ViewModelStore 可以被保存的条件,也就是 onRetainNonConfigurationInstance 调用的条件: due to a configuration change ,手机内存不足及突然没电的场景是不符合的。 关于 ViewModel 保存数据更多的细节可以看看这个问题 每日一问 | ViewModel 在什么情况下的「销毁重建」能够对数据进行无缝恢复?
Activity onRetainNonConfigurationInstance 调用时机 ?
Called by the system, as part of destroying an 阅读更多 ```java class Activity { /** * Called by the system, as part of destroying an * activity due to a configuration change, when it is known that a new * instance will immediately be created for the new configuration. You * can return any object you like here, including the activity instance * itself, which can later be retrieved by calling * {@link #getLastNonConfigurationInstance()} in the new activity * instance. * * If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB} * or later, consider instead using a {@link Fragment} with * {@link Fragment#setRetainInstance(boolean) * Fragment.setRetainInstance(boolean}. * *
This function is called purely as an optimization, and you must * not rely on it being called. When it is called, a number of guarantees * will be made to help optimize configuration switching: *
*
- The function will be called between {@link #onStop} and * {@link #onDestroy}. *
- A new instance of the activity will always be immediately * created after this one's {@link #onDestroy()} is called. In particular, * no messages will be dispatched during this time (when the returned * object does not have an activity to be associated with). *
- The object you return here will always be available from * the {@link #getLastNonConfigurationInstance()} method of the following * activity instance as described there. *
* *
These guarantees are designed so that an activity can use this API * to propagate extensive state from the old to new activity instance, from * loaded bitmaps, to network connections, to evenly actively running * threads. Note that you should not propagate any data that * may change based on the configuration, including any data loaded from * resources such as strings, layouts, or drawables. * *
The guarantee of no message handling during the switch to the next * activity simplifies use with active objects. For example if your retained * state is an {@link android.os.AsyncTask} you are guaranteed that its * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will * not be called from the call here until you execute the next instance's * {@link #onCreate(Bundle)}. (Note however that there is of course no such * guarantee for {@link android.os.AsyncTask#doInBackground} since that is * running in a separate thread.) * *
Note: For most cases you should use the {@link Fragment} API * {@link Fragment#setRetainInstance(boolean)} instead; this is also * available on older platforms through the Android support libraries. * * @return any Object holding the desired state to propagate to the * next activity instance */ public Object onRetainNonConfigurationInstance() { return null; } } ```
ViewModel vs onSaveIntanceState
- onSaveIntanceState 只能存储轻量级的 key-value 键值对数据,非配置变更导致的页面被回收时才会触发,此时数据存储在 ActivityRecord 中;
- ViewModel 可以存放任意 Object 数据,因配置变更导致的页面被回收才有效。此时存在ActivityThread#ActivityClientRecord 中。
SavedState
ViewModel 只能当页面因配置变更而重建时才能复用,但如果是内存不足或者电量不足等系统原因导致的页面被回收时 ViewModel 是不会被复用的
SavedState 能够帮助开发者在 ViewModel 中处理 Activity 和 fragment 状态保存和恢复。
gradle
api 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
LiveData
LiveData 有什么用?
LiveData 组件是 Jetpack 新推出的基于观察者的消息订阅/分发组件,具有宿主(Activity、Fragment)生命周期感知能力,这种感知能力可确保 LiveData 仅分发消息给处于活跃状态(宿主处于 started,resumed 状态)的观察者,即只有处于活跃状态的观察者才能收到消息 。
LiveData 核心原理
相比 Lifecycle 和 ViewModel,LiveData 整体的实现更加的内聚,所有逻辑基本都统一在 LiveData 内实现。
我们就从上面图中列出的有点出发,看看 LiveData 是如何实现数据符合页面状态、不需要手动处理生命周期、数据保持最新状态 等这些功能的。
添加观察者
从我们日常使用 LiveData 的场景出发,看看 observe 的实现。
kotlin
fooViewModel.foo.observe(viewLifecycleOwner, {
text.text = "result is $it"
Log.e(TAG, "$it")
})
java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
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;
}
owner.getLifecycle().addObserver(wrapper);
}
首先会把 LifecycleOwner 和 observer 包装成一个 LifecycleBoundObserver
。 结合上面 UML 图整体的代码架构,可以看到 LifecycleBoundObserver 本质上是一个 ObserverWrapper
。这里的思路和 LifecycleRegistry 的实现非常相似,就是把观察这和其所处的状态做一个封装,便于后面统一维护和更新。
java
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
...
}
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
}
这里就比较有意思,ObserverWrapper
顾名思义,就是包装了一个 Observer. 同时在其内部维护了 mActive 和 mLastVersion 两个成员变量,用于记录当前 Observer 的状态。
LifecycleBoundObserver
(这个命名很贴切,值得学习) 在 ObserverWrapper
的基础上又扩展添加了 LifecycleOwner
。也就是说一个 LifecycleBoundObserver 的实例,做为一个观察者,即有自身的状态,又会感知组件(也就是 Activity/Fragment)的生命周期。这就有意思了。
可以看到在其 onStateChanged
方法中,观察者所在的组件的 state 处于 DESTORY 的时候,会主动移除观察者。就是这么简单,实现了不用处理生命周期,自动实现解除注册的功能。
而如果 currentState 不是 DESTORY 的时候,那么就会进行状态的变更。
java
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
在 while 循环中,如果当前的 state 小于 STARTED .在枚举中,变量的大小是暗含在其声明顺序当中的。
java
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
因此,这里 isAtLeast 返回为 ture,就是说当前状态是 STARTED 或 RESUMED。否则就是 false. 在来看 activeStateChanged
java
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
- 首先就是对比状态的变化,也就是说只有 newActive 的值发生变化,才会继续执行,否则直接 return. 这种什么意思呢? 就是说,如果状态从 STARTED--> RESUMED 或者是 RESUMED->STARTED 。那么
shouldBeActive
始终是 true 。不会变更。简单来说,以 STARTED 为分界线的话,状态在 STARTED、RESUMED 之间变化 或者完全在 DESTROYED、INITIALIZED、CREATED 之间切换时,是不会 shouldBeActive 返回值是不会变化的。而只有当状态越过了这条分界线,才会变化。就会执行changeActiveCounter
方法。 - 而只有 mActive 为 TRUE 的是,也就是状态绝对的处于 STARTED/RESUMED 的时候,才会执行 dispatchingValue 进行数据的分发。这样就做到了数据始终保持最新,而且也不会在应用处于后台的时候更新数据。
- 这里还有一个点,就是 LiveData 所谓的黏性事件,试想,如果我们在添加观察者之前对 LiveData 进行了 setValue/postValue 的操作,那么一旦这里 mActive 的条件成立,就会接收到之前的值,首次添加的 Observer 其 mLastVersion = START_VERSION ,一定是比变更过的当前 LiveData 小的 ,那么一定会进行触发 Observer 的更新(这里的原因,后面有解释)。
更新数据 setValue/postValue
说完了添加观察者,我们再来看看数据更新,首先看 setValue。
setValue
java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
dispatchingValue
java
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
setValue 和 dispatchingValue 整体的逻辑还是比较简单的,就是做一下去重,避免重复发送。 注意,initiator 的类型是 ObserverWrapper 。 当然,这里如果是主动调用 setValue ,那么参数 initiator 为null,就需要遍历所有当前 LiveData 的观察者调用 considerNotify 。 如果是因为当前 LiveData 的状态变更,也就是注册的时候需要变化,那么对当前这一个 Observer 分发就可以了。
最后看 considerNotify 。
considerNotify
java
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
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 (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
considerNotify
的实现虽然看起来很简单,但是每一个行都大有玄机。
- observer.mActive : 添加观察者的阶段,我们就说过了,如果组件处于不可见的状态,那么他的 state 会小于 STARTED ,因此,mActive 就是 false 。 此时,调用 setValue 就会直接返回。因为,这样边保证了页面处于非活动的状态,主动通知也不会想观察者发送数据。
- observer.shouldBeActive() 再次检测,如果代码执行到这里的时候,state 依然变化了,那么就更像 state ,同时返回。
- 数据分发
java
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
这里需要整体来看,如果当前 if 条件为 FALSE。走到了下一行,那么当前这一个 Observer 的 mLastVersion 就和 mVersion 同步了。同时调用 Observer.onChanged 方法,完成数据回调。同时,在整个 LiveData 内部,可以对 mVersion 进行写操作的只有 LiveData 构造函数和 setValue 方法。因此,这里的逻辑就很清楚了,调用 setValue 对 Observer 更新值之后,如果由于其他原因再次发生 considerNotify 。那么只要 mVersion 的值没有更新,那么就不会在调用 onChanged 了,因为数据 mData 肯定没有更新,回调回去的值一定是相同的,那么对于更新 UI 来说就没有意义了,虽然在某些场景下可能有意义。
postValue
java
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
关于 setValue 和 postValue 的区别应该很简单了。这里我们可以想一下,连续多次调用 setValue 和 postValue 会有什么区别?
- 首先对于 setValue 是在 UI 线程执行,那么他一定会保证每一次的调用。因此,观察者一定可以接收到所有的值。但是对于 postValue 来说就不一样了,首先了多线程调用的 synchronized 锁,即便过了锁这一关,
mPendingData
在没有其他地方更新的情况下,postTaks 就是 false.因此整体逻辑直接就 return 了。那么什么时候会更新mPendingData
呢? 我们看 `mPostValueRunnable。 - mPostValueRunnable
java
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
真相只有一个,可以看到只有这个 mPostValueRunnable 被执行了,才会将 mPendingData
初始化。同时可以看到这里的 run 方法里使用了和 postValue 里相同对象锁。也就是说,要么对进行赋值,要么执行。这也是必须的,否则 newValue 的值就可能不是最新的了,就会发生数据丢失的问题。最后,还是调用 setValue 执行具体的数据更新。 但是,从这一点,可以看到连续的调用 postValue 。Observer 获取的值并不会是连续的。
我们可以简单试下
kotlin
class FooViewModel(application: Application) : AndroidViewModel(application) {
val mainValue = MutableLiveData(0L)
val threadValue = MutableLiveData(0L)
fun doUpdate() {
Observable.intervalRange(1,100,1,1,TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {
mainValue.value = it
}
.subscribe()
Observable.intervalRange(1,100,1,1,TimeUnit.MILLISECONDS)
.doOnNext {
threadValue.postValue(it)
}
.subscribe()
}
}
private fun testSetAndPost() {
fooViewModel.mainValue.observe(viewLifecycleOwner, {
Log.e("testSetAndPost", "mainValue =$it")
})
fooViewModel.threadValue.observe(viewLifecycleOwner, {
Log.e("testSetAndPost", "threadValue =$it")
})
fooViewModel.doUpdate()
}
这里暂时忽略 RxJava 的相关问题,只是为了方便演示。我们分别在 主线程和子线程更新 mainValue
和 threadValue
. 然后在任何实现了 viewLifecycleOwner 的组件内观察他们的值。多次执行,可以发现输出结果和我们上面的结论是一致的。
某一种输出 ```shell E/testSetAndPost: mainValue =0 E/testSetAndPost: threadValue =0 E/testSetAndPost: mainValue =1 E/testSetAndPost: mainValue =2 E/testSetAndPost: mainValue =3 E/testSetAndPost: mainValue =4 E/testSetAndPost: mainValue =5 E/testSetAndPost: mainValue =6 E/testSetAndPost: mainValue =7 E/testSetAndPost: mainValue =8 E/testSetAndPost: mainValue =9 E/testSetAndPost: mainValue =10 E/testSetAndPost: mainValue =11 E/testSetAndPost: mainValue =12 E/testSetAndPost: mainValue =13 E/testSetAndPost: mainValue =14 E/testSetAndPost: mainValue =15 E/testSetAndPost: mainValue =16 E/testSetAndPost: mainValue =17 E/testSetAndPost: mainValue =18 E/testSetAndPost: mainValue =19 E/testSetAndPost: mainValue =20 E/testSetAndPost: mainValue =21 E/testSetAndPost: mainValue =22 E/testSetAndPost: mainValue =23 E/testSetAndPost: mainValue =24 E/testSetAndPost: mainValue =25 E/testSetAndPost: mainValue =26 E/testSetAndPost: mainValue =27 E/testSetAndPost: mainValue =28 E/testSetAndPost: mainValue =29 E/testSetAndPost: mainValue =30 E/testSetAndPost: mainValue =31 E/testSetAndPost: mainValue =32 E/testSetAndPost: mainValue =33 E/testSetAndPost: mainValue =34 E/testSetAndPost: mainValue =35 E/testSetAndPost: mainValue =36 E/testSetAndPost: mainValue =37 E/testSetAndPost: mainValue =38 E/testSetAndPost: mainValue =39 E/testSetAndPost: mainValue =40 E/testSetAndPost: mainValue =41 E/testSetAndPost: mainValue =42 E/testSetAndPost: mainValue =43 E/testSetAndPost: mainValue =44 E/testSetAndPost: mainValue =45 E/testSetAndPost: mainValue =46 E/testSetAndPost: mainValue =47 E/testSetAndPost: mainValue =48 E/testSetAndPost: mainValue =49 E/testSetAndPost: mainValue =50 E/testSetAndPost: mainValue =51 E/testSetAndPost: mainValue =52 E/testSetAndPost: mainValue =53 E/testSetAndPost: mainValue =54 E/testSetAndPost: mainValue =55 E/testSetAndPost: mainValue =56 E/testSetAndPost: mainValue =57 E/testSetAndPost: mainValue =58 E/testSetAndPost: mainValue =59 E/testSetAndPost: mainValue =60 E/testSetAndPost: mainValue =61 E/testSetAndPost: mainValue =62 E/testSetAndPost: mainValue =63 E/testSetAndPost: mainValue =64 E/testSetAndPost: mainValue =65 E/testSetAndPost: mainValue =66 E/testSetAndPost: mainValue =67 E/testSetAndPost: mainValue =68 E/testSetAndPost: mainValue =69 E/testSetAndPost: mainValue =70 E/testSetAndPost: mainValue =71 E/testSetAndPost: mainValue =72 E/testSetAndPost: mainValue =73 E/testSetAndPost: mainValue =74 E/testSetAndPost: mainValue =75 E/testSetAndPost: mainValue =76 E/testSetAndPost: mainValue =77 E/testSetAndPost: threadValue =76 E/testSetAndPost: threadValue =77 E/testSetAndPost: mainValue =78 E/testSetAndPost: threadValue =78 E/testSetAndPost: mainValue =79 E/testSetAndPost: threadValue =79 E/testSetAndPost: mainValue =80 E/testSetAndPost: threadValue =80 E/testSetAndPost: mainValue =81 E/testSetAndPost: threadValue =81 E/testSetAndPost: mainValue =82 E/testSetAndPost: threadValue =82 E/testSetAndPost: mainValue =83 E/testSetAndPost: threadValue =83 E/testSetAndPost: mainValue =84 E/testSetAndPost: threadValue =84 E/testSetAndPost: mainValue =85 E/testSetAndPost: threadValue =85 E/testSetAndPost: mainValue =86 E/testSetAndPost: threadValue =86 E/testSetAndPost: mainValue =87 E/testSetAndPost: threadValue =87 E/testSetAndPost: mainValue =88 E/testSetAndPost: threadValue =88 E/testSetAndPost: mainValue =89 E/testSetAndPost: threadValue =89 E/testSetAndPost: mainValue =90 E/testSetAndPost: threadValue =90 E/testSetAndPost: mainValue =91 E/testSetAndPost: threadValue =91 E/testSetAndPost: mainValue =92 E/testSetAndPost: threadValue =92 E/testSetAndPost: mainValue =93 E/testSetAndPost: threadValue =93 E/testSetAndPost: mainValue =94 E/testSetAndPost: threadValue =94 E/testSetAndPost: mainValue =95 E/testSetAndPost: threadValue =95 E/testSetAndPost: mainValue =96 E/testSetAndPost: threadValue =96 E/testSetAndPost: mainValue =97 E/testSetAndPost: threadValue =97 E/testSetAndPost: mainValue =98 E/testSetAndPost: threadValue =98 E/testSetAndPost: mainValue =99 E/testSetAndPost: threadValue =99 E/testSetAndPost: mainValue =100 E/testSetAndPost: threadValue =100 ```
LiveData 扩展
这里就 LiveData 自身的特点做一些延伸和拓展。
取消黏性事件
我们知道 LiveData 是支持黏性事件的。但凡事有利有弊,这样的特性在某些条件下是feature,但在另外一些场景下就变成了问题。下面我们看看如何实现一个更加灵活的 LiveData。
至于黏性事件的原因上面已经分析过了,简单来说,就是新注册的 Observer 其内部的 mLastVersion 小于 LiveData 自身的 mVersion 。如果我们在注册的时候,可以把两者对其,那不就 OK 了吗?具体怎么做呢?首先 ObserverWrapper
内的 mLastVersion 是保内私有的。同时也没有提供在初始化时进行赋值的接口,因此我们是无法直接进行访问的。简单粗暴一些,可以通过反射的方式强行修改这个字段。但是,这样不够优雅,其实我们可以通过代理模式解决这个问题。 version 无法对齐,那我们就手动对齐。
这里我们分别自定义 Observer 和 LiveData ,其中在 PureLiveData
中我们自己维护一个 mVersion ,自定义方法代理 setValue/postValue。同时自定义 Observer,在 PureObserver
中通过自定义的 PureLiveData
中的版本和 stick 字段,决定是否在注册观察者的阶段进行值的分发。
kotlin
class PureObserver<T>(
val data: PureLiveData<T>,
val stick: Boolean = false,
val observer: Observer<in T>
) : Observer<T> {
/**
* 1. 这个值一定是在这里取,这里是这个类创建的时候,也就是添加观察者的时候
* 2. mVersion 是PureLiveData 内部自己维护的 version
*/
private var version = data.mVersion
override fun onChanged(t: T) {
if (version >= data.mVersion) {
// 理论上 version == data.mVersion 就是在注册的时候
if (stick && data.mPureData != null) {
observer.onChanged(data.mPureData)
}
// 如果不支持 stick,那就直接返回吧
return
}
version = data.mVersion
observer.onChanged(data.mPureData)
}
}
class PureLiveData<T> : LiveData<T>() {
internal var mPureData: T? = null
internal var mVersion = 0
fun setData(t: T) {
this.mPureData = t
super.setValue(t)
}
fun postData(t: T) {
this.mPureData = t
super.postValue(t)
}
override fun setValue(value: T) {
mVersion++
super.setValue(value)
}
override fun postValue(value: T) {
mVersion++
super.postValue(value)
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
observePure(owner, observer, false)
}
fun observePure(owner: LifecycleOwner, observer: Observer<in T>, stick: Boolean) {
super.observe(owner, PureObserver(this, stick, observer))
}
}
总结
好了,Jetpack 最常用的几个组件暂时就分析这么多。可以看到 Lifecycle/ViewModel/LiveData 的源码实现是非常巧妙的,尤其是 LiveData,有很多值得学习和借鉴的点。很多实现非常的巧妙,值得我们实践到日常的开发中。
当然了,关于这个三个组件,每过一段时间阅读其源码都会有不一样的收获,都会有一些新的思考。本次阅读理解接到这里,权当是现阶段的理解,后面如果有新的体会,有更高层次的理解,再次补充。