ViewModel源码解析

概览

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 activity,是在 activity 完成时;而对于 fragment,是在 fragment 分离时。

如下图生命周期:

在系统首次调用 Activity 对象的 onCreate() 方法时请求 ViewModel。系统可能会在 activity 的整个生命周期内多次调用 onCreate(),如在旋转设备屏幕时。ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 activity 完成并销毁。

特点

  • 1.横竖屏切换,包括Activity重建,数据可依然保存。
  • 2.同一个Activity下,Fragment之间的数据共享。同理在不同Activity中也可以共享ViewModel数据

源码分析

我们在使用时是这样创建viewmodel的:

1
ViewModelProviders.of(this).get(MyViewModel::class.java)

从上看出,Factory不传,默认为null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
// getViewModelStore是在父类FragmentActivity中的;
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}

但是在2.2.0 中 ViewModelProviders被弃用。需要用新的方式获取:

1
ViewModelProvider(this,ViewModelProvider.NewInstaanceFactory()).get(MyViewModel::class.java)

接着看ViewModelStoreOwner,就是this,说明它是一个接口,并且,我们的Activity一定是实现了这个接口。

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
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
// 就是拿到ViewModelStore,如果是高版本,这里应该还有个nc判断,android-28版本nc在onCreate里
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
// nc保存了viewModelStore,所以横竖屏切换,数据不会丢失。
if(mViewModelStore == null){
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
}

if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}

//mViewModelStore专门存储ViewModel
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}

看以下继承关系:

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
public class FragmentActivity extends ComponentActivity implements
ViewModelStoreOwner,
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
}
// 这个接口只有一个ViewModelStore
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
// ViewModelStore是啥?就是存储了一个map,map里存的是viewmodel,同时提供了一个clear方法,用于清理map缓存。
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);
}

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

接着看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
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);

if (modelClass.isInstance(viewModel)) {//缓存里是否有,有就直接返回。
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}

viewModel = mFactory.create(modelClass);//通过mFactory创建ViewModel
mViewModelStore.put(key, viewModel);//存储到mViewModelStore
//noinspection unchecked
return (T) viewModel;//并返回ViewModel
}

那Factory如何根据class创建ViewMoel的?通过反射,拿到我们自定义的MyViewModel

1
2
3
4
5
6
7
 public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (Exception e) {
}
}

所以,ViewModelProvider(this,ViewModelProvider.NewInstaanceFactory()).get(MyViewModel::class.java)这段代码一执行。就会通过工厂NewInstaanceFactory,反射实例化MyViewModel存储到了ViewModelStore中。
那viewmodel是啥时候销毁的?是在onDestroy生命周期中,所以,这里不需要我们手动去做,框架帮我们做了。同理,无论activity如何操作,旋转,重建,viewmode都不会销毁,数据都会保存,只有最后销毁,才清除掉。同时跟lifecycle解绑。

1
2
3
4
5
6
7
protected void onDestroy() {
super.onDestroy();
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}

参考资料

developer.android.google.cn