• android被杀以后fragments缓存重建问题和测试方法


    这个问题,其实不是太好复现。因为在android的缓存Fragment机制是写在androidx的库中。

    主要的原因是android Framework机制:

    framework
    at yourpackage.onSaveInstanceState(XXXActivity.kt:118)
    at android.app.Activity.performSaveInstanceState(Activity.java:2283)
    at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1508)
    at android.app.ActivityThread.callActivityOnSaveInstanceState(ActivityThread.java:5878)
    at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:5281)
    at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:5247)
    at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5312)
    at android.app.servertransaction.StopActivityItem.execute(StopActivityItem.java:43)
    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:17
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2259)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    主要流程:
    ActivityThread->onPause|onStop|performDestroyActivity|callActivityOnStop|handleRelaunchActivity
    Instrumentation-> callActivityOnSaveInstanceState
    activity->onSaveInstanceState

    即,当activity发生了需要停止和隐藏的时候,或者Relaunch等等情况,根据具体的尝尽是否进行保存。因为大部分情况是不会触发的。
    只要后台不做app保活的情况,手机内存回收的情况等才会触发。

    app

    然后onSaveInstanceState就到app代码+androidx库代码了,不同的androidx版本或者之前的android.support版本是不同的:

        override fun onSaveInstanceState(outState: Bundle) {
            super.onSaveInstanceState(outState)
            //val e = Exception()
            //e.printStackTrace()
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个是你自己的activity。然后调用super。即追溯到
    androidx:activity库 ComponentActivity,
    androidx:savestate库 SavedStateRegistryController | SavedStateRegistry.performSave,
    outBundle.putBundle(SAVED_COMPONENTS_KEY, components) //“androidx.lifecycle.BundlableSavedStateRegistry.key”

    接着,就是FragmentAcitvity的FragmentManager,对于SavedStateRegistry的注册。将

     		//SAVED_STATE_TAG = "android:support:fragments";
            registry.registerSavedStateProvider(SAVED_STATE_TAG, () -> {
                        return saveAllStateInternal();//里面进行缓存Fragment
                    }
            );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总结就是framework提供了暂存的触发条件,app的库内部支持了缓存机制。

    模拟方案和调试手段

    其实更重要的是:你平时无法复现,而测试或者用户出现了。
    这里提供几个思路:

    1. 开发者选项,不保留活动打开。这样每次按home回到launcher,再次进,是会触发onSaveInstanceState的;
    2. 把程序按home放到后台去。如果你有蓝牙权限,可以尝试在应用管理里面,把蓝牙权限关闭,三星手机android13必定触发,因为关闭蓝牙权限,他会立刻结束对应的app。再次切回来,就会重建;
    3. 在需要调试的Fragment代码中,在构造函数里面,或者kotlin的init{}函数,添加
               val e = Exception()
             e.printStackTrace()
      
      • 1
      • 2
      可以十分方便的看到framework-androidx的代码逻辑。

    修改方案如下:

       override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
            super.onSaveInstanceState(outState, outPersistentState)
            removeCachedFragments(outState)
        }
    
        override fun onSaveInstanceState(outState: Bundle) {
            super.onSaveInstanceState(outState)
            removeCachedFragments(outState)
        }
    
        private fun removeCachedFragments(outState: Bundle) {
            if (false) { //非androidx 自行根据情况开启。
                outState.putParcelable("android:support:fragments", null)
                outState.putParcelable("android:fragments", null)
            } else { //androidx
                outState.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key")?.let {
                    it.remove("android:support:fragments")
                    it.remove("android:fragments")
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    其他:
    三星手机还有一个问题,当关闭应用管理-蓝牙权限,app会立刻死掉进程。然后拉起的是你最后的activity。
    如果你有一些初始化逻辑放在SplashActivity或者前置的一些地方,则会导致初始化不正常。
    所以需要考虑将一些逻辑放到application的初始化中去。

  • 相关阅读:
    LeetCode //C - 9. Palindrome Number
    代码随想录算法训练营第七天|二叉树(截止到层序遍历)
    C++ 笛卡尔树
    vue3 setup(基础版)
    Git常用方法
    有趣之matlab-烟花
    Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台
    常用工具链和虚拟环境-WSL
    3分钟,快速上手Postman接口测试!
    0909hw
  • 原文地址:https://blog.csdn.net/jzlhll123/article/details/133273783