Android异常退出时Activity数据的保存和恢复

时间:2024-05-21 16:38:20

本文章是基于Kotlin版的简单Activity-Fragment状态切换及数据保留的探讨,原问题如下:
Android异常退出时Activity数据的保存和恢复
页面长时间放置后台,或者在其他页面crash后,退到主页面,发现智护页面出现重叠。
该页面架构简单:主Activity对两个Fragment,一个智护Fragment,一个报告Fragment。

一、Activity创建时读取数据

正常情况下Activity的生命周期比较简单,这里就不详细叙述了,不清楚的可以自行百度~
Activity在创建的时候会执行生命周期的OnCreate方法,该方法的参数为Bundle类型。那么这个数据是从哪里得来的呢?

override fun onCreate(savedInstanceState: Bundle?) {
}

1、Activity如何保持数据

当横竖屏切换时,Activity会被销毁,生命周期方法onPause,onStop,onDestory等均会被调用,此时Activity属于异常情况下终止的,所以系统会调用onSaveInstanceState方法对Activity的状态进行保存。该方法在onStop之前调用,与onPause没有既定的时序关系。
当出现Crash时,除了其他的生命周期方法不会执行外,也会执行保存数据的操作。
当Activity被重新创建后,系统会调用onRestoreInstanceState,将之前onSaveInstanceState保存的数据Bundle传递给onRestoreInstanceState和onCreate方法,因此我们可以通过onRestoreInstanceState和onCreate方法判读Activity是否被重建了,如果被重建了,那么我们就可以取出之前保存的数据并进行恢复,onRestoreInstanceState的调用时机在onStart之后。
注意:正常情况下Activity的创建和销毁不会调用onSaveInstanceState和onRestoreInstanceState方法。

	// 此方法用来保存当前异常退出的Activity的数据 
 override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
        super.onSaveInstanceState(outState, outPersistentState)
    }

	// 此方法用来重载当前异常退出的Activity的数据
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        super.onRestoreInstanceState(savedInstanceState)
    }

我们只需要在onSaveInstanceState中保存需要存储的参数,然后再onRestoreInstanceState获取保存的数据并进行设置即可。

2、Activity恢复数据

OnCreate方法的Bundle类型参数,其实和onRestoreInstanceState中的Bundle参数是一样的,不过需要我们自己进行判断,而onRestoreInstanceState如果Bundle为Null时则不会调用。因此我们也可以对onCreate方法的Bundle参数进行判断,当Bundle不为null时对数据进行恢复。

2、如何防止Activity重建

1、设置Activity的方向固定

onCreate方法中设置 但是这种情况不适合手机已经设置为自动旋转的情况。需要在清单文件下设置
android:screenOrientation=“portrait”

//
 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
 

2、Manifest清单设置

不仅仅当屏幕方向切换时会重建Activity,当系统配置发生改变的时候Activity都会被重建,例如用户插入外接键盘,运营商改变,界面模式(例如开启夜间模式)等都会导致Activity重建。如果我们不希望当系统配置发生变化界面重建,那么我们需要在AndroidManifest.xml中对Activity的configChange属性进行配置。例如我们不希望屏幕旋转时重建,则需要如下设置:

android:screenOrientation="portrait"
android:configChanges="orientation"

3、解决上述问题

因为Activity的重建,导致图中的问题出现。

解决方式一:

使用tag标记Fragment,再次使用的时候判断该Fragment是否销毁:

var monitorFragment = fragmentManager.findFragmentByTag("monitor")
                monitorFragment?.let {
                    fragmentTransaction.show(it)
                }?:let {
                    monitorFragment = MonitorFragment()
                    fragmentTransaction.add(R.id.fg_content,monitorFragment,"monitor")
                }

解决方式二:

在Oncreate方法中,判断savedInstanceState是否为空,如果不为空,直接finish掉,直接让当前页面挂掉(实用于负责页面,复杂数据,避免引发更多的错误)。

override fun onCreate(savedInstanceState: Bundle?) {
        if (savedInstanceState != null){
            finish()
        }
}

其实和Activity类似,Fragment也有onSaveInstanceState的方法,在此方法中进行保存数据,然后在onCreate或者onCreateView或者onActivityCreated进行恢复都可以。网上相关文章很多,学习不能停,如果你愿意,总能发现惊喜!