JetPack 之 ViewModel

ViewModel仍然是Model的范畴,是数据对象的载体,但是多了与视图(View)生命周期的绑定关系。可以简单理解为带有生命周期的数据对象。可在Activity, Fragment中使用,保证其在生命周期内的唯一性和一致性,不受配置的更改(例如屏幕旋转)。

ViewModel生命周期

下图可以看出,ViewModel的生命周期和Activity/ Fragment一样甚至更长,因为如果发生屏幕旋转,ViewModel并没有跟着销毁,直到最终的onDestroy。

ViewModel的使用

使用Android的ViewModel,需要在gradle添加引用:

1
implementation 'android.arch.lifecycle:extensions:1.1.1'

ViewModel的声明 千万不能持有Context的引用,否则会引起内存泄漏,如果实在需要Context,可以继承AndroidViewModel,通过getApplication()获取Application。

1
2
3
public class CustomModel extends ViewModel {
public CustomObj obj;//业务内需要使用的对象
}

在代码中使用ViewModel。

1
2
3
4
5
6
public class MyActivity extends Activity {
public void myFunction() {
CustomModel customModel = ViewModelProviders.of(MyActivity.this).get(CustomModel.class);
customModel.obj...//自己操作该对象
}
}

ViewModel的实现原理

通过上面的实例我们可知 :

  • 多个ViewModel存储在ViewModelStore中,本质上是一个Map存储的键值对。keyViewModel的名字或者get方法时自己设置的key
  • 先查找ViewModelStore中是否含有该实例,有则直接返回,没有则通过反射的方式得到实例,并加入ViewModelStore中。
  • ViewModelProviders.of(activity/fragment),通过activity/fragment拿到Application,当然AndroidViewModel也是通过反射拿到初始实例的,和ViewModel不同的是它需要将application传过去。

ViewModelStoreandroid support包和androidx下存储ViewModel的方式完全不同,但是暴露给我们使用的方法却是不变的。

  • android support包中的实现:

    • ViewModel本质上属于Activity/ Fragment级别,通过FragmentManager/ChildFragmentManager插入一个没有ViewHolderFragmentViewModelStore即保存在HolderFragment中
    • onCreatesetRetainInstance(true), 保证屏幕旋转时fragment不被销毁;
    • HolderFragmentonDestroy时回调ViewModelStore.clear,循环调用ViewModelStore.onCleared
  • androidx包中的实现:

    • ViewModel仍然属于Activity/Fragment级别,只是ViewModelStore是分别存储在FragmentActivityFragment中;
    • Activity销毁重建过程是通过onRetainNonConfigurationInstance()getLastNonConfigurationInstance()保存和还原的ViewModelStore对象的;
    • Fragment中的ViewModelStore会在配置变化的时候缓存在FragmentManagerNonConfig对象(包括不被销毁的fragment集合,循环嵌套的子FragmentFragmentManagerNonConfig集合以及所有FragmentViewModelStore集合),它们在FragmentActivity重建onCreate时还原每个FragmentViewModelStore对象,可以说ViewModelStore的存储介质是正常被销毁的,只是ViewModelStore数据被保存并在特定场景下还原回来,保存和还原都是由FragmentActivity主动触发的;
    • 如果是由配置更改导致Activity/Fragment onDestroy则不清除ViewModelStore的数据,反之则清除。

总之,不管采用不销毁ViewModelStore的存储介质,还是采用保存再还原数据的方式,都能保证在当前作用域下数据的唯一性和完整性。

参考文章