Android应用崩溃重启以及被系统Kill场景分析

Android应用崩溃重启

Android应用开发过程中,当我们的应用发生Crash时异常退出,然后又自动启动跳转到未知页面,此时应用在崩溃前保存的全局变量被重置,用户状态丢失,显示数据错乱。

不同场景表现的现象

经测试,在 Android 的 API 21 ( Android 5.0 ) 以下,Crash 会直接退出应用,但是在 API 21 ( Android 5.0 ) 以上,系统会遵循以下原则进行重启:

  1. 包含Service,如果应用Crash的时候,运行着Service,那么系统会重新启动Service。
  2. 不包含Service,只有一个Activity,那么系统不会重新启动该Activity。
  3. 不包含Service,但当前堆栈中存在两个Activity:Act1 -> Act2,如果Act2发生了Crash,那么系统会重启Act1。
  4. 不包含Service,但是当前堆栈中存在三个 Activity:Act1 -> Act2 -> Act3,如果 Act3 崩溃,那么系统会重启Act2,并且Act1依然存在,继续返回即可以从重启的Act2回到Act1。
解决思路
  1. 允许应用自动重启,并在重启时恢复应用在崩溃前的运行状态。

  2. 禁止应用自动重启,而是让用户在应用发生崩溃后自己手动重启应用

为主线程设置Thread.UncaughtExceptionHandler接口,监听崩溃异常

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
                // 监听应用的crash,做相应的逻辑处理
            }
        });
    }
}

Android系统Kill应用进程

当我们的App切换至后台时,比如按下了Home键,此时App不再与用户交互,该App所在的进程处于一个较低的优先级,那么系统内存运行不足的情况,很可能被系统杀死。比如目前运行的前台应用,需要较多的资源内存等,那么系统会尽可能的分配给它,那么后台低优先级的进程很可能被系统kill。此时kill进程,Activity等并不是执行正常的生命周期,比如onDestroy()方法不会被执行。

Android系统恢复应用进程

Android系统人性化的一个方面,当我们的应用被系统kill掉之后,会保留当时的一个记录信息,方便下次帮助我们恢复。就是说人家把我们的进程kill掉之后,还是会想办法帮助我们恢复的。具体的场景是当我们重新点击Launch icon时,这时候Application会重新创建,走其生命周期,并帮助我们恢复进程被kill之前用户停留的页面,也就是栈顶的Activity。注意系统默认只会帮助我们创建这个Activity,至于栈中其它的Activity当我们按下返回键时,系统会帮我们一层一层创建恢复。

应用进程系统Kill之后的兼容处理
  1. Android应用被进程kill之后,进程内存都被回收,再次开启应用,静态变量等全部被重新初始化,那么如果当前有访问到一些静态变量,那么思考是否为空。可以考虑Local Storage(本地存储一份)
  2. Intent中Bundle存值可靠性,这里面的信息,系统会帮我们记录,再次恢复会传递给我们,所以时比较安全的。
  3. onSaveInstanceState()和onRestoreInstanceState()保存和恢复方法,Android应用被系统Kill之后,恢复时会调用onRestoreInstanceState()方法,将Kill前保留的信息,传递过来,所以我们可以在onSaveInstanceState()中进行存值,方便我们恢复时取出。
模拟这种场景

手机开发者选项,选择不保留后台进程,打开App,按下Home键退居后台,这时再尝试打开其它应用,然后再回到我们的原先的App,就可以观察应用被kill重新启动的流程

不使用系统默认的恢复机制,当我们检测到应用被Kill之后,我们自己重新启动。

1.应用被kill之后,好多静态变量被回收,容易发生空指针异常,如果我们一个一个去检测,避免不了代码过于复杂,以及可能发生遗漏,那么当这种情况出现时,我们可以尝试重新开启应用,执行我们正常的启动流程,这样的话逻辑流程我们可控,除了问题,也好排查。
2.如何检测到当前应用发生了进程kill被系统恢复,这个思路应该很多,比如Application里设置一个静态变量,SplashActivity的onCreate对其赋值,其它Activity每次onCreate检测这个值,如果不合法则判断时进程被kill重新恢复了(因为在恢复的时候没有新建SplashActivity所以这个静态变量是初始化值)
3.当检测到系统被kill重新恢复时,Applcaiton已经被系统创建,这时候我们可以打开应用的启动页,清除任务栈,进入正常的启动流程。

总结
  1. Android系统会为每一个应用分配一定的内存,当系统内存不足时,Android系统会按照进程回收机制来杀死一部分应用,并回收内存提供给其他的应用;

  2. 应用被系统杀死后,应用中所有的数据都会被回收掉,但是Activity提供了一定的补救措施,应用中的Activity栈还是会保存下来,并且提供了onSaveInstanceState和onRestoreInstanceState来恢复界面数据,因为需要重新创建Activity对象,需要耗费一定时间,所以可能会有短暂的白屏现象;

  3. 面对大量要恢复的数据(特别是静态变量),如果我们采用恢复数据的方式来处理应用被系统杀死的问题,代码将会很复杂,我们必须非常小心的处理数据恢复的问题,并且数据恢复也存在一定的效率问题,毕竟需要将数据持久化;

  4. 针对应用被杀死的问题,可以采用重新初始化应用流程的方式来解决,也就是如果发现应用时非正常启动,则清空当前Activity栈,并且去启动应用的欢迎界面,这样就相当于重新打开应用一样,这种处理方式虽然没有应用被杀死前的数据,但是处理起来简单方便。

你可能感兴趣的:(Android,Android应用崩溃重启,Android系统Kill应用,Android应用稳定性)