ViewModel相关生命周期的原理分析-之三
1个回答
展开全部
前面介绍了ViewModel的生命周期,知道了其会在宿主activity或者fragment销毁时被销毁(config change造成的除外);如下图:
但是没有深究其中的原理,虽然这并不影响我们的使用;但是为了知识的完成性,我们最好还是深入分析下其中的原理,同时,一些设计思想还是非常巧妙的,个人觉得是有很借鉴价值的。
首先让我们回顾下ViewModel的获取方式
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
前面也说过,这其实是从创建的ViewModelProvider中得到ViewModelStore;而ViewModelStore是和宿主实例一一对应的;从ViewModelStore中获取相应classmodel对应的ViewModel实例;因此ViewModel生命周期其实是与ViewModelStore一致的;我们从这里入手进行分析,为什么config change(例如,屏幕旋转)造成的宿主销毁不会影响ViewModel的生命周期呢?
需要分开进行分析;
当ViewModel的宿主是普通的activity或者fragment的时候,需要利用HolderFragment来保证config change时的生命周期,其原理如下
可见;对于normal宿主,会通过holderFragmentFor(activity)返回的HolderFragment来得到ViewModelStore实例;宿主和HolderFragment一一对应;
宿主对应的HolderFragment持有相应的ViewModelStore
主要逻辑都在HolderFragmentManager中;其主要原理是利用了嵌套fragment;需要用到的一些基础知识
参考 https://www.cnblogs.com/mengdd/p/5552721.html
在宿主fragment里调用getChildFragmentManager()
即可用它来向这个fragment内部添加fragments.
Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();
同样, 对于内部的fragment来说, getParentFragment() 方法可以获取到fragment的宿主fragment.
看起来HolderFragment 是嵌套子Fragment
总结就是: getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者.
这实际上是一个树形管理结构.
参考 https://blog.csdn.net/gaugamela/article/details/56280384
已保留的fragment不会随着activity一起被销毁; 相反,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。
当设备配置发生变化时,FragmentManager首先销毁队列中fragment的视图(因为可能有更合适的匹配资源);
紧接着,FragmentManager将检查每个fragment的retainInstance属性值。如果retainInstance属性值为false,FragmentManager会立即销毁该fragment实例。
随后,为适应新的设备配置,新的Activity的新的FragmentManager会创建一个新的fragment及其视图。
Activity遇到config change时会先保存状态
activity stop时会根据情况调用onSaveInstanceState以保存状态
调用到FragmentController,FragmentManager来进行保存
对所有active fragment和嵌套的fragment进行识别;如果 mRetainInstance = true;则用 FragmentManagerNonConfig 进行保存
将fragment对象持有住
可以看到保存fragment对象的大致逻辑; 从Activity的生命周期状态中触发,调用FragmentController->FragmentManager从而将设置了 setRetainInstance (true)的fragment的相关fragment保存起来;这样config change时fragment不会执行到onDestroy; 对于HolderFragment而言,不会执行到其onDestory方法,ViewModelStore及其对应ViewModel均会得以保留
还原的是后也是相似的路径还原的,将 FragmentManagerNonConfig 保存的对象还原出来,添加到相关队列里
保持了屏幕旋转时不会调用onDestroy; 同时又持有 ViewModelStore实例对象,从而维护了其生命周期
那么activity或者fragment作为宿主如何和HolderFragment对应的呢?
首先看activity的holderFragmentFor(activity)
相当于通过fragmentManager.add添加一个无View的HolderFragment,其持有ViewModelStore的引用,并将mRetainInstance置为true,保证了config change时的生命周期
可见HolderFragment是宿主fragment的嵌套子fragment;
宿主activity/fragment怎么保持和HolderFragment实例的对应关系呢?
通过mNotCommittedActivityHolders和mNotCommittedFragmentHolders进行映射,相当于一个backup缓存;HolderFragment的onCreate会进行清理(config change还原时不会走到HolderFragment的onCreate);
监听到宿主destory的时候会进行清理,宿主销毁时要将对应的映射也删去,清空缓存;
到此为止我们就大致明白了normal activity/fragment作为宿主时是如何保证ViewModel的生命周期的;不得不说这个设计还是很巧妙的,一个简单的fragment就实现了对ViewModelStore的维护; (我觉得这个思路值得我们借鉴,可以保存ViewModel,那是否可以保存其他东西呢? )
因为support类型的宿主实现了ViewModelStoreOwner;所以就无需HolderFragment辅助了,而是系统内部已经帮我们实现好了;
((ViewModelStoreOwner) activity).getViewModelStore();注意这里,直接从宿主中getViewModelStore成员变量,那么是如何保存的呢?
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2497
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2734
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ActivityThread.java#4595
ensureActivityConfiguration->relaunchActivityLocked-----binder call----------->handleRelaunchActivity (监听到config变化,走relaunch逻辑,将mChangingConfigurations置为true,这样Activity的ViewModelStore不会clear)
r.activity.mChangingConfigurations = true;
这里会将mViewModelStore保存下来
会在activity 要被destory的时候将需要的东西保存下来
然后再onCreate的时候重新还原; mViewModelStore对象还原了,且前面又没有清掉里面保存的ViewModel对象,这样就做到了config change但是不销毁ViewModel;
如果宿主是fragment
也就是说就算调用了onDestory;只要mStateSaved = true,也不会清掉mViewModelStore
但是没有深究其中的原理,虽然这并不影响我们的使用;但是为了知识的完成性,我们最好还是深入分析下其中的原理,同时,一些设计思想还是非常巧妙的,个人觉得是有很借鉴价值的。
首先让我们回顾下ViewModel的获取方式
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
前面也说过,这其实是从创建的ViewModelProvider中得到ViewModelStore;而ViewModelStore是和宿主实例一一对应的;从ViewModelStore中获取相应classmodel对应的ViewModel实例;因此ViewModel生命周期其实是与ViewModelStore一致的;我们从这里入手进行分析,为什么config change(例如,屏幕旋转)造成的宿主销毁不会影响ViewModel的生命周期呢?
需要分开进行分析;
当ViewModel的宿主是普通的activity或者fragment的时候,需要利用HolderFragment来保证config change时的生命周期,其原理如下
可见;对于normal宿主,会通过holderFragmentFor(activity)返回的HolderFragment来得到ViewModelStore实例;宿主和HolderFragment一一对应;
宿主对应的HolderFragment持有相应的ViewModelStore
主要逻辑都在HolderFragmentManager中;其主要原理是利用了嵌套fragment;需要用到的一些基础知识
参考 https://www.cnblogs.com/mengdd/p/5552721.html
在宿主fragment里调用getChildFragmentManager()
即可用它来向这个fragment内部添加fragments.
Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();
同样, 对于内部的fragment来说, getParentFragment() 方法可以获取到fragment的宿主fragment.
看起来HolderFragment 是嵌套子Fragment
总结就是: getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者.
这实际上是一个树形管理结构.
参考 https://blog.csdn.net/gaugamela/article/details/56280384
已保留的fragment不会随着activity一起被销毁; 相反,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。
当设备配置发生变化时,FragmentManager首先销毁队列中fragment的视图(因为可能有更合适的匹配资源);
紧接着,FragmentManager将检查每个fragment的retainInstance属性值。如果retainInstance属性值为false,FragmentManager会立即销毁该fragment实例。
随后,为适应新的设备配置,新的Activity的新的FragmentManager会创建一个新的fragment及其视图。
Activity遇到config change时会先保存状态
activity stop时会根据情况调用onSaveInstanceState以保存状态
调用到FragmentController,FragmentManager来进行保存
对所有active fragment和嵌套的fragment进行识别;如果 mRetainInstance = true;则用 FragmentManagerNonConfig 进行保存
将fragment对象持有住
可以看到保存fragment对象的大致逻辑; 从Activity的生命周期状态中触发,调用FragmentController->FragmentManager从而将设置了 setRetainInstance (true)的fragment的相关fragment保存起来;这样config change时fragment不会执行到onDestroy; 对于HolderFragment而言,不会执行到其onDestory方法,ViewModelStore及其对应ViewModel均会得以保留
还原的是后也是相似的路径还原的,将 FragmentManagerNonConfig 保存的对象还原出来,添加到相关队列里
保持了屏幕旋转时不会调用onDestroy; 同时又持有 ViewModelStore实例对象,从而维护了其生命周期
那么activity或者fragment作为宿主如何和HolderFragment对应的呢?
首先看activity的holderFragmentFor(activity)
相当于通过fragmentManager.add添加一个无View的HolderFragment,其持有ViewModelStore的引用,并将mRetainInstance置为true,保证了config change时的生命周期
可见HolderFragment是宿主fragment的嵌套子fragment;
宿主activity/fragment怎么保持和HolderFragment实例的对应关系呢?
通过mNotCommittedActivityHolders和mNotCommittedFragmentHolders进行映射,相当于一个backup缓存;HolderFragment的onCreate会进行清理(config change还原时不会走到HolderFragment的onCreate);
监听到宿主destory的时候会进行清理,宿主销毁时要将对应的映射也删去,清空缓存;
到此为止我们就大致明白了normal activity/fragment作为宿主时是如何保证ViewModel的生命周期的;不得不说这个设计还是很巧妙的,一个简单的fragment就实现了对ViewModelStore的维护; (我觉得这个思路值得我们借鉴,可以保存ViewModel,那是否可以保存其他东西呢? )
因为support类型的宿主实现了ViewModelStoreOwner;所以就无需HolderFragment辅助了,而是系统内部已经帮我们实现好了;
((ViewModelStoreOwner) activity).getViewModelStore();注意这里,直接从宿主中getViewModelStore成员变量,那么是如何保存的呢?
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2497
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2734
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ActivityThread.java#4595
ensureActivityConfiguration->relaunchActivityLocked-----binder call----------->handleRelaunchActivity (监听到config变化,走relaunch逻辑,将mChangingConfigurations置为true,这样Activity的ViewModelStore不会clear)
r.activity.mChangingConfigurations = true;
这里会将mViewModelStore保存下来
会在activity 要被destory的时候将需要的东西保存下来
然后再onCreate的时候重新还原; mViewModelStore对象还原了,且前面又没有清掉里面保存的ViewModel对象,这样就做到了config change但是不销毁ViewModel;
如果宿主是fragment
也就是说就算调用了onDestory;只要mStateSaved = true,也不会清掉mViewModelStore
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询