ViewModel是Android Architecture Components中提供的一个组件,其做用是为UI组件提供须要展示的数据内容,帮助开发者更优雅简单高效的实现多个组件间的数据共享。其中值得注意的是ViewModel的生命周期,以往咱们将UI展现的数据直接缓存在对应的UI组件中,遇到ConfigurationChange等事件UI组件从新建立,咱们缓存的数据也随之销毁。但ViewModel能够在内存中长期被持有而不受ConfigurationChange的影响,直到相关联的UI组件真正销毁的时候ViewModel才随之释放。下面是来自官方的对ViewModel生命周期的描述图:html
本文主要探讨文章标题提到的问题,关于ViewModel的细节介绍能够参阅官方文档。java
若是堆代码不如本身去阅读源码,那样反而来的更清晰直观。因此后面的部分不会打源码战术,可是也有一些我的分析的过程描述,若是只关心黑科技是啥,能够直接跳到最后结论部分。android
由官方的demo咱们能够看到使用ViewModel的简单方法以下:git
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// 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.
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
复制代码
咱们须要实现一个派生自ViewModel的类。接着在须要的UI组件中经过ViewModelProviders.of().get()来获取咱们定义的ViewModel实例。demo中看到真正使用时每每在ViewModel中以LiveData来封装须要UI组件展示的数据,因而在获取咱们定义的ViewModel实例后即可以经过其内部的LiveData来添加观察者,进而实现数据变动时能及时的通知到UI组件。关于LiveData的细节介绍能够参阅官方文档。 咱们仍是回到ViewModel。就以demo中看到的ViewModelProviders为切入点。github
我画了一张类图,打算尝试按照本身的理解将他们的关系讲清楚,那也就基本了解为何ViewModel对ConfigurationChange免疫了。也为你们查阅源码或者提出异议提供一个思路。缓存
图中虚线箭头表示依赖关系,箭头尾部对应的类依赖箭头头部对应的类。 中间的实线箭头表示类的组合关系,箭头尾部对应的类中包含箭头头部对应的类的实例。app
ViewModel对ConfigurationChange免疫,换个角度能够理解为在不一样的UI组件实例中获取的ViewModel实例相同。 根据demo得知,咱们经过ViewModelProviders.of().get()这样一个链式调用来获取ViewModel实例。 因此要得到一个ViewModel分为两个步骤:async
第一步,调用ViewModelProviders.of()方法获取一个ViewModelProvider实例。这正是图中左上部分表达的信息:ide
ViewModelProvider依赖于ViewModelProviders,ViewModelProvider是经过ViewModelProviders提供的一系列of方法构造出来的。经过ViewModelProvider的构造方法的定义能够看到在构造时须要传入ViewModelStore和Factory。ViewModelStore是真正缓存ViewModel的地方,Factory则用于在缓存未命中时建立ViewModel。fetch
第二步,经过ViewModelProvider.get()方法获取ViewModel实例,这从图中的ViewModelProvider和ViewModelStore的关系能有所体现:
ViewModelProvider内部有一个ViewModelStore类型的成员变量mViewModelStore和一个用于建立ViewModel的Factory成员变量mFactory。他们是在建立对象时经过构造方法传入的。调用ViewModelProvider.get()方法实际上是经过内部的ViewModelStore.get()方法来获取ViewModel,而若是获取为空,则经过mFactory构建一个新的ViewModel。
ViewModelStore中保存一个Map键值对,这里是真正缓存ViewModel的地方,因此ViewModelProvider.get()最终会调到ViewModelStore的这个Map中来找缓存的ViewModel。 由于最终是从ViewModelStore的Map键值对中查找缓存的ViewModel,因此要保证ViewModel的惟一性其实就是保证ViewModelStore的惟一性。 前面提到ViewModelProvider中的mViewModelStore是先经过ViewModelStores构造好,而后利用其构造方法传递到ViewModelProvider中的。因此接下来的重点就是ViewModelStores如何构造一个ViewModelStore。
ViewModelStore经过ViewModelStores构造,其构造过程须要图中的ViewModelStores和HolderFragment类一块儿完成。 从图中能够看到ViewModelStore是经过ViewModelStores.of()方法来构造的,ViewModelStores.of()方法内部会直接调用HolderFragment的静态方法holderFragmentFor(),该静态方法返回一个HolderFragment对象,这个HolderFragment对象就是一个派生自Fragment的类,只不过它不包含任何View树结构。接着调用它的getViewModelStore()方法返回HolderFragment的成员变量mViewModelStore,这个mViewModelStore是做为成员变量在HolderFragment类加载时直接new出来的。因此一个HolderFragment对象必定对应惟一一个ViewModelStore对象实例。同时这个mViewModelStore实例会做为前面构造ViewModelProvider时的参数传进去。也就是说ViewModelProvider和HolderFragment中的mViewModelStore对象指向的是同一个实例,这个实例是先在HolderFragment中构造初始化以后传递到ViewModelProvider中去的。 既然ViewModelStore是经过HolderFragment建立出来的,一个HolderFragment实例内部惟一对应一个ViewModelStore实例,那如今的问题就变成如何保证HolderFragment的惟一性了。 到这里,黑科技终于登场。其实就是利用Fragment的setRetainInstance()方法。经过在实例化HolderFragment的时候调用该方法,并传入true做为参数。HolderFragment就能够在其宿主的Fragment或Activity重走生命周期时在内存中持久化其自身实例,即此时Fragment对应的View会从View树中移除,可是Fragment实例自己不会销毁,在下一次宿主Fragment或Activity重走生命周期时会复用内存中持久化的Fragment实例。以此来达到HolderFragment实例的惟一性。关于setRetainInstance()方法的使用详情能够参阅官方文档。