Android ViewMode源码分析
ViewMode的谷歌官方介绍如下:
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
翻译过来就是:ViewModel类旨在以生命周期意识的方式存储和管理与UI相关的数据。 ViewModel类允许数据在配置更改(例如屏幕旋转)后继续存在。
既然谷歌官方说它有以生命周期意识,那我们就来看看它是怎么做到的;首先就是看它的基本用法,通过它的调用方式一层一层往下看它的源码实现;这个例子就采用谷歌官方的例子了,具体如下:
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
这里我们先不要纠结它例子中的MutableLiveData和LiveData,这并不是我们的重点。
定义好了模型我们就看怎么使用:
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
使用过程中我们要关注文档上标红的警告:
A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
警告:ViewModel绝不能引用视图,生命周期或任何可能包含对活动上下文的引用的类。
以上就是ViewModel的使用,然而的生命周期如下图:
viewmodel-lifecycle.png
看了图片之后你可能会好奇她是怎么做到的呢,那接下来我们就通过它的使用方法来看它是怎么做到的。
首先我们看ViewModelProviders.of(this)这个方法做了什么,点进去之后我们发现它调用了重载方法:
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
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(ViewModelStores.of(activity), factory);
}
这里我们只要关注下面的方法即可,第一行代码就是检查Application
private static Application checkApplication(Activity activity) {
Application application = activity.getApplication();
if (application == null) {
throw new IllegalStateException("Your activity/fragment is not yet attached to "
+ "Application. You can't request ViewModel before onCreate call.");
}
return application;
}
当调用的时候传递的是fragment时,就会多调用一个方法如下:
private static Activity checkActivity(Fragment fragment) {
Activity activity = fragment.getActivity();
if (activity == null) {
throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
}
return activity;
}
当然了这两个方法对于我们调用和理解源码不太重要,就跳过了,最重要的是这个Factory和它的返回值,那下面我们就先来看看它的Factory是怎么创建的
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
点进去之后发现就是ViewModelProvider中的一个普通静态内部类,继承了ViewModelProvider中的NewInstanceFactory,这两个类代码如下:
/**
* Simple factory, which calls empty constructor on the give class.
*/
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
/**
* {@link Factory} which may create {@link AndroidViewModel} and
* {@link ViewModel}, which have an empty constructor.
*/
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
/**
* Retrieve a singleton instance of AndroidViewModelFactory.
*
* @param application an application to pass in {@link AndroidViewModel}
* @return A valid {@link AndroidViewModelFactory}
*/
@NonNull
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
/**
* Creates a {@code AndroidViewModelFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
*/
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
}
把它俩放一块对比之后你会发现原来这个简单,NewInstanceFactory就只有一个create方法,这个create()方法就直接通过Class创建了对象,而AndroidViewModelFactory的create()方法则是调用了一个传递了Application对象的方法。
好了这个Factory是干啥的我们了解了之后我们就看这个ViewModelProvider是如何创建的,代码如下:
return new ViewModelProvider(ViewModelStores.of(activity), factory);
这行代码就是创建了一个ViewModelProvider,然后传递了两个参数一个是ViewModelStore,一个是上面分析的Factory,那接下来我们看看
ViewModelStores.of(activity)干了啥,代码如下:
/**
* Returns the {@link ViewModelStore} of the given activity.
*
* @param activity an activity whose {@code ViewModelStore} is requested
* @return a {@code ViewModelStore}
*/
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
首先它判断我们传递的FragmentActivity是不是ViewModelStoreOwner,并且ViewModelProvider的of()方法要求的类也是 FragmentActivity, 那么我们就得看看FragmentActivity这个类是不是实现了ViewModelStoreOwner接口或者继承了ViewModelStoreOwner这个类,点到FragmentActivity之后发现他已经实现了ViewModelStoreOwner接口,并重写了唯一的方法getViewModelStore();下面是FragmentActivity类中的实现:
@NonNull
public ViewModelStore getViewModelStore() {
if (this.getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
} else {
if (this.mViewModelStore == null) {
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null) {
this.mViewModelStore = nc.viewModelStore;
}
if (this.mViewModelStore == null) {
this.mViewModelStore = new ViewModelStore();
}
}
return this.mViewModelStore;
}
}
总之就是进行了一系列的校验之后判断是否已经有了ViewModelStore实例,如果没有就创建了ViewModelStore实例。
看到这你大概应该也快晕了吧,这是什么鬼,调用来调用去,创建了这么多的对方,然而就只是创建了一个ViewModelProvider实例而已,对应我们的代码就是:
ViewModelProviders.of(this)
那接下来的问题就是ViewModelProvider的get()方法了,这个方法倒是简单,代码如下:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//首先从mViewModelStore中获取,mViewModelStore内部就是存储了ViewModel的map,
//key是android.arch.lifecycle.ViewModelProvider.DefaultKey:ViewModel类名
//value是ViewModel实例
ViewModel viewModel = mViewModelStore.get(key);
//判断viewModel实例是否为空,不为空直接返回
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//到这一步说明ViewModel还没有进行初始化,那么通过调用
//前面分析传递的AndroidViewModelFactory对象实例调用create()方法创建实例,并保存进ViewModelStore中,方便下次直接获取
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
目前代码到这里我们就梳理出了ViewModel的创建过程和缓存机制,其实就是在自己创建的Activity的父类中的FragmentActivity中的ViewModelStore保存了跟activity相关的所有ViewModel对象,然后在FragmentActivity中的onDestroy()方法中对数据进行了清空,代码如下:
//FragmentActivity中的onDestroy
protected void onDestroy() {
super.onDestroy();
if (this.mViewModelStore != null && !this.isChangingConfigurations()) {
this.mViewModelStore.clear();
}
this.mFragments.dispatchDestroy();
}
//ViewModelStore中的clear()
/**
* 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();
}
到这里我们就看到了它是如何跟activity的生命周期进行绑定的;其实就是系统在FragmentActivity中自定义了一个Map,然后保存了跟这个Activity相关的ViewModel,在onDestroy的时候对这个Map进行了清空数据操作,在进行清空之前对Activity的重新创建进行了判断,就是调用了!this.isChangingConfigurations()。好了到这里大概的流程就基本梳理完了,主要是有了这种思想之后再去回顾一下源码你就会感觉逻辑很清晰。