这个问题,其实不是太好复现。因为在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)
主要流程:
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()}
这个是你自己的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});
总结就是framework提供了暂存的触发条件,app的库内部支持了缓存机制。
模拟方案和调试手段
其实更重要的是:你平时无法复现,而测试或者用户出现了。
这里提供几个思路:
- 开发者选项,不保留活动打开。这样每次按home回到launcher,再次进,是会触发onSaveInstanceState的;
- 把程序按home放到后台去。如果你有蓝牙权限,可以尝试在应用管理里面,把蓝牙权限关闭,三星手机android13必定触发,因为关闭蓝牙权限,他会立刻结束对应的app。再次切回来,就会重建;
- 在需要调试的Fragment代码中,在构造函数里面,或者kotlin的init{}函数,添加
可以十分方便的看到framework-androidx的代码逻辑。val e = Exception()e.printStackTrace()
修改方案如下:
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 { //androidxoutState.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key")?.let {it.remove("android:support:fragments")it.remove("android:fragments")}}}
其他:
三星手机还有一个问题,当关闭应用管理-蓝牙权限,app会立刻死掉进程。然后拉起的是你最后的activity。
如果你有一些初始化逻辑放在SplashActivity或者前置的一些地方,则会导致初始化不正常。
所以需要考虑将一些逻辑放到application的初始化中去。