Android 异常情况下的生命周期分析

异常情况下的生命周期分析

一:资源相关的系统配置发生改变导致Activity被杀死并重新创建(以旋转屏幕为例)

样例代码,

首先再onSaveInstanceState中存储一个字符串,然后当 Activity被销毁并重新创建的时后,再去获取之前存储的字符串。接收的位置可以在 onRestoreInstanceState 或者onCreate,二者的区别是: onRestoreInstanceState 一旦被调用其参数Bundle savedInstanceState一定是有值的,不需要额外判空;但onCreate不行,因为onCreate如果是正常启动,其参数Bundle savedInstanceStatenull,所以必须进行额外判断。官方推荐采用 onRestoreInstanceState 进行恢复数据。

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState != null){
            String test = savedInstanceState.getString("test");
            Log.d(TAG, "[onCreate] restore extra_test: " + test);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
        Log.d(TAG,"onSaveInstanceState");
        outState.putString("test","test");
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String test = savedInstanceState.getString("test");
        Log.d(TAG,"[onRestoreInstanceState] restore test: " + test);
    }

当旋转屏幕后,运行的日志如下:

日志分析

当系统配置发生改变后,Activity 会被销毁,其onPause、onStop、onDestroy 均会被调用,同时由于Activity 是在异常情况下终止的,系统会调用 onSaveInstanceState 来保存当前Activity的状态。这个方法的调用时机是在 onStop 之前,它和 onPause 没有既定的时序关系,它既可能在onPause之前调用,也可能在onPause之后调用。(当Android api为28时,onStop会在其之前,即 onSaveInstanceState 出现在 onStop之后,onDestroy之前,与日志情况相符)需要强调的一点是,这个方法只会出现在Activity 被异常终止的情况下,正常情况下系统不会回调这个方法。当 Activity 被重新创建后,系统会调用 onRestoreInstanceState, 并且把Activity 销毁时onSavelnstanceState 方法所保存的Bundle 对象作为参数同时传递给 onRestoreInstanceState和 onCreate 方法。因此,我们可以通过 onRestoreInstanceState 和 onCreate 方法来判断Activity是否被重建了,如果被重建了,那么我们就可以取出之前保存的数据并恢复,从时序上来说,onRestorelnstanceState 的调用时机在onStart之后。

onSaveInstanceState调用时机

  1. 当用户按下HOME键时。 这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
  2. 长按HOME键,选择运行其他的程序时
  3. 按下电源按键(关闭屏幕显示)时
  4. 从activity A中启动一个新的activity时
  5. 屏幕方向切换时,例如从竖屏切换到横屏时。

onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)

避免当系统配置发生改变后,Activity被重新创建

configChanges属性添加值

例如解决旋转屏幕的重新创建:android:configChanges="orientation|screenSize"

主要使用的几个值

  • keyboardHidden : 键盘的可访问性发生了改变,例如调出了键盘
  • orientation : 屏幕方向发生了改变,例如旋转了屏幕
  • screenSize : 当屏幕的尺寸信息发省了改变,当旋转屏幕时,屏幕尺寸会发生改变,但这个选项比较特殊和编译选项有关,当编译选项中的 minSdkVersion 和 targetSdkVersion 均低于13时,此选项不会导致 Activity 重启,否则会导致 Activity 重启(API 13 新添加)
  • locale : 设备的本地位置发生了改变,一般指切换了系统语言

二:资源内存不足情况导致低优先级的Activity被杀死

这种情况我们不好模拟,但是其数据存储和恢复过程和情况一完全一致。这里我们描述一下Activity的优先级情况。Activity 按照优先级从高到低,可以分为如下三种:

  1. 前台Activity-- 正在和用户交互的Activity, 优先级最高。

  2. 可见但非前台Activity——比如 Activity中弹出了一个对话框,导致Activity可见,但是位于后台无法和用户直接交互。

  3. 后台Activity--已经 被暂停的Activity,比如执行了onStop, 优先级最低。

当系统内存不足时,系统就会按照上述优先级去杀死目标 Activity 所在的进程,并在后续通过 onSaveInstanceState 和 onRestoreInstanceState 来存储和恢复数数据。如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死,因此,一些后台工作不适合脱离四大组件而独自运行在后台中,这样进程很容易被杀死。比较好的方法是将后台工作放入Service中从而保证进程有一定的优先级,这样就不会轻易地被系统杀死。

posted @ 2020-10-12 17:37  花染梦  阅读(323)  评论(0编辑  收藏  举报