logo头像

我有一个梦想

LiveData和ViewModel源码分析

本文于 909 天之前发表,文中内容可能已经过时。

[TOC]

ViewModel

ViewModel的定义

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

历史方式的缺点

  1. 对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
  2. 需要处理异步调用,内存泄漏等问题
  3. 使界面控制器类越发膨胀

ViewModel将数据存储和界面控制进行分离,独立出来
ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁。

ViewModel生命周期

img

ViewModel在onCreate中初始化,在finish()后会调用onCleared()方法,

所以ViewModel生命周期长于Activity,ViewModel不持有UI的引用,通过观察者通知界面更新

ViewModel在Fragment之间共享数据

为什么能在Fragment中共享数据?
因为在Fragment中初始化ViewModel时传入的宿主Activity,ViewModelStore中取出当前Activity对应的ViewModel对象,返回给Fragment,这样他们获取的是同一个ViewModel实例,数据当然也会共享

ViewModel源码分析

构造函数

我们通常使用这种方式初始化ViewModel

1
2
3
4
5
6
7
ProgressViewModel processViewModel = new ViewModelProvider(this).get(ProcessViewModel.class);

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}

从ViewModelStoreOwer中获取ViewModelStore,ViewModelStore是从AppCompatActivity->FragmentActivity->ComponentActivity中获取,本质还是new ViewModelStore()。
Factory在AppCompatActivity和Fragment中的是HasDefaultViewModelProviderFactory,具体实现是SavedStateViewModelFactory

1
2
3
4
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}

将ViewModelStore和Factory进行赋值

get方法

进入get方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
//返回该类的规范名称,如果它是本地或匿名类或其组件类型没有规范名称的数组,则返回null。
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
//key = DEFAULT_KEY + ":" + canonicalName
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//从ViewModelStore中获取ViewModel,首次进入获取为空
ViewModel viewModel = mViewModelStore.get(key);

//等效于instanceOf,判断是否是所需viewModel
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}

我们可知
Factory放入具体实现是SavedStateViewModelFactory,SavedStateViewModelFactory又继承于KeyedFactory,我们看下create方法,值得一提的是,这里的mFactory是AndroidViewModelFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
//是否为AndroidViewModel类,或者其子类
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// doesn't need SavedStateHandle
//如果constructor为null,create内部什么也不处理
if (constructor == null) {
return mFactory.create(modelClass);
}

SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if (isAndroidViewModel) {
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
return viewmodel;
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An exception happened in constructor of "
+ modelClass, e.getCause());
}
}

判断ViewModel类型,获取不同的构造方法,通过反射实现ViewModel的初始化,然后使用mViewModelStore.put(key, viewModel); 将viewModel以key的形式存入ViewModelStore
进入ViewModelStore:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    public class ViewModelStore {

private final HashMap<String, ViewModel> mMap = new HashMap<>();

final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}

final ViewModel get(String key) {
return mMap.get(key);
}

Set<String> keys() {
return new HashSet<>(mMap.keySet());
}

/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}


内部实现就是一个HashMap,Key为String,value为ViewModel,put后新放入的ViewModel覆盖新的ViewModel,这里的key强调一下,统一格式为androidx.lifecycle.ViewModelProvider.DefaultKey:com.zz.chatright.ChatViewModel

SavedState

在源码分析中我们看到构造函数中都包含了一个SavedStateHandleController类,这里保存了数据类,使其不受生命周期影响,例如发生屏幕旋转等。

img

  • SaveStateHandle:
    内部存储数据格式为Map<String, Object>,亦存在Map<String, SavingStateLiveData<?>>完成值的通知
  • SaveStateHandleController:
    将SaveStateHandle同Lifecycle生命周期进行绑定
  • SavedStateRegistry:
    管理 SavedStateProvider 列表的组件,此注册表绑定了其所有者的生命周期(即 activity 或 fragment)
  • SavedStateProvider:
    保存状态的组件,此状态将在以后恢复并使用

activity 的状态保存分为 view 状态和成员状态

继承关系

img

如何保证viewModel的唯一性?

通过反射进行初始化操作,带入的是Application的Context对象,这样就保证不会持有Activity或者Fragment的引用。然后会将创建出来的实例对象存储在ViewModelStore(内部HashMap)中,每次使用都会去ViewModelStore中查看是否存在,如果存在,则直接使用,不需要实例化
key就是DEFAULT_KEY + “:” + canonicalName(viewmModel类名路径,eg:com.zz.test.MyViewModel)

为什么viewModel能管理生命周期,并且不受重建情况的影响

2.0以前:创建了一个无view的HolderFragment同步Activity的生命周期,并关联ViewModelStore,而且设置setRetainInstance(true)时,会保证屏幕切换时生命周期不会改变,让fragment在Activity重建时存活下来

2.0以后:运用了androidx新库,用到了AppCompatActivity的父类ComponentActivity,重写onRetainNonConfigurationInstance()方法保存了ViewModelStore,Activity通过onRetainNonConfigurationInstance()方法获取ViewModelStore实例,保证了ViewModel不会随着Activity的重建而重建。
不论是Activity还是Fragment都实现了LifecycleOwner,所以生命周期通过Lifecycles组件感知每个页面的生命周期

onRetainNonConfigurationInstance()和onSaveInstanceState的调用时机是一样的,但是onRetainNonConfigurationInstance()的Bundle数据不限制大小,所以更倾向这个

当Activity因为配置需要重建时,系统会调用onRetainNonConfigurationInstance()方法,将ViewModelStore存储在NonConfigurationInstances中,最终交给ActivityClientRecord类,因为ActivityClientRecord不受Activity重建的影响,所以NoConfigurationInstances也不受Activity重建的影响

ViewModel同onSaveInstanceState()的区别

使用场景

在Activity变得“容易”销毁时,就会触发onSaveInstanceState()

  1. 当按下HOME键后,系统就会触发调用
  2. 当长按HOME键,选择运行其他程序时
  3. 按电源键息屏的时候
  4. 从Activity A中启动一个新的Activity
  5. 横竖屏切换时

而使用ViewModel恢复数据 则 只有在 因配置更改界面销毁重建 的情况。

存储方式

ViewModel存储在内存中,onSaveInstanceState()是序列化到磁盘中存储的

存储大小

ViewModel存储大小限制时app的可用内存
onSaveInstanceState()因为使用了序列化和反序列化,那么通过Bundle存储大小限制为1M

LiveData

LiveData的定义

img

当在onStart后,onResume,onPause都是STARTED/RESUMED的,即为活跃的(onActive),当在onStop后,则为非活跃状态(onInActive)
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。

LiveData的优势

  1. 及时更新界面数据
  2. 不会发生内存泄漏,当其关联的生命周期被摧毁,则回收自己
  3. 不会因为Activity停止而崩溃,准确判断生命周期,决定是否通知
  4. 不需要自己手动处理生命周期
  5. 在再次活跃时会接收到最新的数据,保持数据最新状态
  6. 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
  7. 共享资源。
    您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。

LiveData源码分析

建立号viewModel后,我们在Activity中这样使用:

1
2
3
processViewModel.isBigScreen.observe(appCompatActivity, it -> {
...
});

进入observe方法进行查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//如果该生命周期为onDestory之后,则return,不做处理
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将观察者注册到mObservers中,如果存在,则返回wrapper,否则,返回null
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);
}

通常我们使用setValue和postValue的方法进行数据更新
进入setValue下查看:
1
2
3
4
5
6
7
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}

进入dispatchingValue()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
}

便利订阅者集合,进行分发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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.
//如果不是onResume状态
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//通过version判断是否是最新数据
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
//执行分发逻辑
observer.mObserver.onChanged((T) mData);
}

在active的生命周期下,如果是onResume状态且是最新数据,则进行数据分发,否则,进入activeStateChanged方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
}
}

当不是active状态下,则不会进行分发处理,当页面从后台回到前台时,也会触发该方法,那么会取最新的mData并分发给该页面。

如果是post请求,会通过handler传递到主线程,调用setvalue方法,所有的回掉,observer方法都是在主线程中的