ViewModel相关生命周期的原理分析-之三

 我来答
会哭的礼物17
2022-06-02 · TA获得超过1.2万个赞
知道大有可为答主
回答量:5973
采纳率:100%
帮助的人:32.6万
展开全部
前面介绍了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
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式