最近一个月主要实现了IM功能,其中UI框架使用了ViewModel和LiveData的存储和通知机制,实现后代码简洁易于维护。
感慨于Android arch components控件强大同时,须要顺带分析一波其中源码实现。今天先来分析一下ViewModel的源码实现。java
ViewModel是经过关联生命周期的方式来存储和管理跟UI相关的数据。即便configuration发生变化,在ViewModel中存放的数据是不会被销毁的。
没使用ViewModel的时候,若是系统Configuration发生变化,咱们的Activity会被销毁重建,致使Activity中的UI数据丢失。为了规避这个问题,咱们只能在onSaveInstanceState()将UI数据进行保存,在onCreate方法中判断savedInstanceState中是否有咱们存储的数据。
有了ViewModel以后,咱们只须要将数据存储到ViewModel便可,ViewModel中的数据不会随着Activity的销毁重建而消失。同时,若是不一样的Fragment使用相同的Activity对象来获取ViewModel,能够轻易的实现数据共享和通讯。app
使用ViewModel的例子:框架
// 自定义一个ViewModel,存储一个字符串 public class TestViewModel extends ViewModel { public String content; @Override protected void onCleared() { // 数据清理工做 content = null; } } // 在Activity中获取并使用ViewModel TestViewModel viewModel = ViewModelProviders.of(activity).get(TestViewModel.class); Log.d("tag", viewModel.content);
我我的习惯,看源码时候老是要带着问题去分析理解,这样才会有所收获。ide
经过示例代码,去掉链式调用后,咱们能够看到ViewModel是经过以下两步建立出来的:函数
// 1. 建立ViewModelProvider ViewModelProvider viewModelProvider = ViewModelProviders.of(activity); // 2. 经过反射获取ViewModel TestViewModel viewModel = viewModelProvider.get(TestViewModel.class);
先看下第一步的源码实现:源码分析
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { if (factory == null) { // 若是传入的对象建立工厂类为null,则使用默认的AndroidViewModelFactory来建立对象 factory = AndroidViewModelFactory.getInstance(application); } // 建立一个ViewModelProvider return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory); }
源码中,咱们发现建立一个ViewModelProvider须要传入两个参数:ViewModelStore和Factory。咱们先看下Factory的实现。学习
Factory顾名思义,定义了建立ViewModel的行为接口。里面只有一个create方法,用于子类自行决定如何实现一个ViewModel对象的建立。this
public interface Factory { <T extends ViewModel> T create(@NonNull Class<T> modelClass); }
同时,ViewModelProvider源码内部也提供了两个默认Factory实现:NewInstanceFactory和AndroidViewModelFactory。google
// 直接反射Class对象的无参构造函数来建立ViewModel public static class NewInstanceFactory implements Factory { @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { 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); } } } // 1. 若是对象继承自AndroidViewModel,发射调用带Application参数的构造函数建立ViewModel对象; // 2. 若是对象不继承自AndroidViewModel,则直接调用父类,即调用Class的无参构造函数建立ViewModel对象。 public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory { private static AndroidViewModelFactory sInstance; @NonNull public static AndroidViewModelFactory getInstance(@NonNull Application application) { if (sInstance == null) { sInstance = new AndroidViewModelFactory(application); } return sInstance; } private Application mApplication; 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); } }
启示:咱们自定义的ViewModel对象若是构造函数中须要其余各类参数,咱们只须要建立一个自定义的Factory类,而后调用该class的有参构造函数进行建立便可。spa
ViewModelStore就是个HashMap,经过key来获取ViewModel对象。
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.get(key); if (oldViewModel != null) { oldViewModel.onCleared(); } mMap.put(key, viewModel); } final ViewModel get(String key) { return mMap.get(key); } }
了解了Factory实现和ViewModelStore实现后,咱们来看一下ViewModelProvider的get方法是如何建立ViewModel对象的。
public class ViewModelProvider { private final Factory mFactory; private final ViewModelStore mViewModelStore; public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; this.mViewModelStore = store; } public <T extends ViewModel> T get(@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } @NonNull @MainThread public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) { ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { return (T) viewModel; } viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; } }
ViewModleProvider的get方法实现也比较简单,总结一下就是:
至此,第一个问题ViewModel是如何建立出来的已经分析完毕。接下来,咱们看第二个问题。
讲道理,若是同窗们仔细看了ViewModel的建立流程,这个问题天然迎刃而解。
由于不一样的Fragment使用相同的Activity对象来获取ViewModel,在建立ViewModel以前都会先从Activity提供的ViewModelStore中先查询一遍是否已经存在该ViewModel对象。因此咱们只须要先在Activity中一样调用一遍ViewModel的获取代码,便可让ViewModel存在于ViewModelStore中,从而不一样的Fragment能够共享一份ViewModel了。
在看这个问题以前,咱们回到ViewModelProviders.of()源码中:
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { if (factory == null) { // 若是传入的对象建立工厂类为null,则使用默认的AndroidViewModelFactory来建立对象 factory = AndroidViewModelFactory.getInstance(application); } // 建立一个ViewModelProvider return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory); }
ViewModelProvider获取ViewModelStore是经过ViewModelStores.of(activity)实现的。咱们先看一下这个ViewModelStores作了什么操做。
看名字又像是一个封装好的工厂类。看下源码:
public static ViewModelStore of(@NonNull FragmentActivity activity) { return activity instanceof ViewModelStoreOwner ? ((ViewModelStoreOwner)activity).getViewModelStore() : HolderFragment.holderFragmentFor(activity).getViewModelStore(); }
经过源码能够发现,若是Activity是ViewModelStoreOwner的实现类,则直接经过activity获取ViewModelStore,若是不是,则经过HolderFragment.holderFragmentFor(activity).getViewModelStore()来获取。
经过查看FragmentActivity源码,发现其已是实现了ViewModelStoreOwner接口。
public class FragmentActivity extends BaseFragmentActivityApi16 implements ViewModelStoreOwner, ActivityCompat.OnRequestPermissionsResultCallback, ActivityCompat.RequestPermissionsRequestCodeValidator { }
因此这里咱们已经不须要理会HolderFragment了,不少分析ViewModel源码的文章都会花不少篇幅分析HolderFragment,我实在是搞不懂为何要这种操做。(初步怀疑是互相抄袭。。.)
虽然FragmentActivity实现了ViewModelStoreOwner接口,可以提供ViewModelStore,可是ViewModelStore是如何跟Activity生命周期关联起来的呢?
搜索了一下FragmentActivity中关于ViewModelStore的调用,发现这里的实现应该跟生命周期处理有关。
google搜索了一下Activity的onRetainNonConfigurationInstance的做用:大部分同窗知道Activity由于configuration变化销毁和重建时会调用onSaveInstanceState和onRestoreInstanceState。与此同时,Activity其实还会回调onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法。
onRetainNonConfigurationInstance和onSaveInstanceState做用相同,用来保存UI相关变量,当Activity意外销毁时,Activity的ViewModelStore对象就是在这里进行了保存。
那什么时机进行的恢复呢?
当Activity的onCreate调用时,会调用getLastNonConfigurationInstance,获取以前保存的ViewModelStore,若是ViewModelStore不为空,就进行赋值。这里进行了ViewModelStore的恢复。
这里咱们又学到了Activity的两个跟生命周期相关的函数调用:onRetainNonConfigurationInstance和getLastNonConfigurationInstance。
三个问题分析完毕,相信你们已经对ViewModel的实现原理比较熟悉了。建议你们之后学习源码时,也带着问题去分析思考,事半功倍。