Activity & Fragment 的重建、数据恢复相关问题解惑
展开全部
我们经常在网上看到说, onSaveInstanceState 在 Activity 退回到后台,且未来可能被系统杀死时,我们可以在 onSaveInstanceState 中保存一些临时数据,以便在系统真的杀死了进程,并回收了 Activity 后,用户回到 Activity 时,开发者能够在重建的 Activity 的 onCreate 或 onRestoreInstanceState 方法中,能够从 Bundle 中恢复数据。
这两个回调的时机不一样。
我们知道在屏幕旋转时 Activity 和 Fragment 会重建,其实还有一种情况会重建,就是我们时常看到博客里说的,当应用在后台时,进程被系统回收,用户再次回到应用时,应用会被重建。
那么应用什么时候会被系统回收呢?我们需要清楚一点,就是系统不会单独地回收 Activity 或者 Fragment ,而是会在系统资源不足时,根据应用所在的进程的状态来杀死进程,以回收资源。这里涉及到了一些进程状态的概念:前台进程、可见进程、服务进程 和 缓存进程( process lifecycle )。一般缓存进程会最先被系统回收。
现在的手机 RAM 都非常大,我们怎么模拟这个系统回收进程的过程呢?可以到 开发者选项 -> 应用 -> 后台进程限制 ,将其从默认的 标准限制 改为 不得超过 1 个进程 。这样我们就能够观察到 Activity 或 Fragment 重建时, Bundle 中带有之前调用 onSaveInstanceState 时保存的值了。
Fragement 的数据恢复提供了另外两个回调, onCreate 和 onCreateView ,方便开发者在不同的时机恢复数据。
Fragment 的 retainInstance 属性默认为 false ,当其设置为 true 时,表示 Fragment 实例会在 Activity 因配置变化而重建时, Fragment 自身实例会被保持,不会创建新的实例。它的原理是,调用该方法时,最终调用到了 FragmentManager.addRetainedFragment -> FragmentManagerViewModel.addRetainedFragment , Fragment 实例保存到了 FragmentManagerViewModel.mRetainedFragments 中。 mRetainedFragment 是一个以 Fragment 的 uuid( Fragment 自己生成) 为 key ,以 Fragment 自身实例为 value 的 HashMap 。因此本质上是因为 FragmentManagerViewModel 是一个 ViewModel ,它可以在重建周期内保持实例。
正确的使用姿势应该是, onSaveInstanceState 和 ViewModel 结合使用。
我们知道 onSaveInstanceState 中保存的是能够被序列化的数据, Android 系统同样为我们提供了在配置改变时保存没有必要序列化的数据的方法: onRetainCustomNonConfigurationInstance 和 onRetainNonConfigurationInstance ,这两个回调方法都返回一个 Object ,区别在于, onRetainCustomNonConfigurationInstance 是开放给开发者来保存数据的时机的回调, onRetainNonConfigurationInstance 是 final 方法,用于系统自己保存一些系统资源时使用。
对于 onRetainCustomNonConfigurationInstance 保存的数据,之后我们在重建的 Activity 的 onCreate 方法中,可以通过 getLastCustomNonConfigurationInstance 来直接获得之前保存的数据。这个回调在 Androidx 中已经被标记为 Deprecated ,这是因为该机制的职责已经由 ViewModel 代替了。
对于 onRetainNonConfigurationInstance 保存的数据,其实通过阅读源码我们是可以发现,目前的实现就是用来保存了 ViewModel 。而 ViewModel 之所以能够在系统配置改变后重建,正是使用了 onRetainNonConfigurationInstance 的恢复机制。
ViewModel 的重建恢复原理
这两个回调的时机不一样。
我们知道在屏幕旋转时 Activity 和 Fragment 会重建,其实还有一种情况会重建,就是我们时常看到博客里说的,当应用在后台时,进程被系统回收,用户再次回到应用时,应用会被重建。
那么应用什么时候会被系统回收呢?我们需要清楚一点,就是系统不会单独地回收 Activity 或者 Fragment ,而是会在系统资源不足时,根据应用所在的进程的状态来杀死进程,以回收资源。这里涉及到了一些进程状态的概念:前台进程、可见进程、服务进程 和 缓存进程( process lifecycle )。一般缓存进程会最先被系统回收。
现在的手机 RAM 都非常大,我们怎么模拟这个系统回收进程的过程呢?可以到 开发者选项 -> 应用 -> 后台进程限制 ,将其从默认的 标准限制 改为 不得超过 1 个进程 。这样我们就能够观察到 Activity 或 Fragment 重建时, Bundle 中带有之前调用 onSaveInstanceState 时保存的值了。
Fragement 的数据恢复提供了另外两个回调, onCreate 和 onCreateView ,方便开发者在不同的时机恢复数据。
Fragment 的 retainInstance 属性默认为 false ,当其设置为 true 时,表示 Fragment 实例会在 Activity 因配置变化而重建时, Fragment 自身实例会被保持,不会创建新的实例。它的原理是,调用该方法时,最终调用到了 FragmentManager.addRetainedFragment -> FragmentManagerViewModel.addRetainedFragment , Fragment 实例保存到了 FragmentManagerViewModel.mRetainedFragments 中。 mRetainedFragment 是一个以 Fragment 的 uuid( Fragment 自己生成) 为 key ,以 Fragment 自身实例为 value 的 HashMap 。因此本质上是因为 FragmentManagerViewModel 是一个 ViewModel ,它可以在重建周期内保持实例。
正确的使用姿势应该是, onSaveInstanceState 和 ViewModel 结合使用。
我们知道 onSaveInstanceState 中保存的是能够被序列化的数据, Android 系统同样为我们提供了在配置改变时保存没有必要序列化的数据的方法: onRetainCustomNonConfigurationInstance 和 onRetainNonConfigurationInstance ,这两个回调方法都返回一个 Object ,区别在于, onRetainCustomNonConfigurationInstance 是开放给开发者来保存数据的时机的回调, onRetainNonConfigurationInstance 是 final 方法,用于系统自己保存一些系统资源时使用。
对于 onRetainCustomNonConfigurationInstance 保存的数据,之后我们在重建的 Activity 的 onCreate 方法中,可以通过 getLastCustomNonConfigurationInstance 来直接获得之前保存的数据。这个回调在 Androidx 中已经被标记为 Deprecated ,这是因为该机制的职责已经由 ViewModel 代替了。
对于 onRetainNonConfigurationInstance 保存的数据,其实通过阅读源码我们是可以发现,目前的实现就是用来保存了 ViewModel 。而 ViewModel 之所以能够在系统配置改变后重建,正是使用了 onRetainNonConfigurationInstance 的恢复机制。
ViewModel 的重建恢复原理
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询