Android之Activity生命周期(二)

Activity异常生命周期

上一篇分析了常规典型情况的Activity的生命周期,我们知道,Activity除了用户正常操作所导致的调用生命周期之外,还有一些异常情况,比如说当资源相关的系统配置发生改变以及内存不足的时,Activity很有可能被杀死。接下来还是先看下Activity整个生命周期的方法:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private TextView mTvContent;
    /**
     * activity正在创建中,生命周期中的第一个方法。
     * 在这个方法中可以做一些初始化工作,比如setContentView加载布局及初始化所需数据
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate()");

        if (savedInstanceState != null) {
            count = savedInstanceState.getInt("count", 0);
        }
    }

    private int count;

    /**
     * activity正在启动中,这时activity是可见的,但还没有处于前台的位置,是无法和用户交互的。
     */
    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart()");
    }

    /**
     * activity已经可见了,并且出现在前台了开始活动了,用户可以操作屏幕会响应的。
     * 与onStart方法相比,都是activity可见状态,但onStart是处于后台,而onResume是在前台的。
     */
    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume()");
    }


    /**
     *activity正在停止,一般情况下紧接着onStop会被调用
     * 此时可以在此方法总做一些停止动画或数据存储工作,但不能太耗时
     * 因为这会影响到新的activity的启动显示,旧的activity被执行完后,
     * 新activity的onResume方法才会执行
     */
    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause()");
    }

    /**
     * activity即将停止,可以做一些资源释放工作,但不能太耗时
     */
    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop()");
    }

    /**
     * activity正在重新启动。一般情况下当前activity从不可见状态到可见状态时
     * onRestart会被执行,这个情形下一般是用户行为所导致的,比如按Home键返回桌面
     * 或启动一个新activity,这时当前的activity就是执行onPause和onStop方法
     * 当用户又回到了这个activity时,就是调用onRestart
     */
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart()");
    }

    /**
     * activity即将销毁,是activity生命周期中最后一个方法,
     * 可以在里面做一些资源的回收释放工作。
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy()");
    }


    /**
     * 在此方法内允许保存Activity的实例状态
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("count", count);
        Log.i(TAG, "onSaveInstanceState()");
    }

    /**
     *可以获取之前保存Activity的实例状态
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstanceState()");
        count = savedInstanceState.getInt("count", 0);
        mTvContent.setText(String.valueOf(count));
    }

     /**
     * 当给Activity指定了android:configChanges属性值,会调用此方法
     * 会改变Activity生命周期的调用
     */
 @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.d(TAG, "onConfigurationChanged: "+newConfig.orientation);
        super.onConfigurationChanged(newConfig);
    }

}

一、资源相关系统配置发生改变所导致Activity被杀死并重新创建

1、系统默认情况下,当打开新Activity或者按Home键返回桌面,Activity的回调以下方法:

03-24 20:06:41.520 21691-21691/com.hzw.tapp I/MainActivity: onPause()
03-24 20:06:42.226 21691-21691/com.hzw.tapp I/MainActivity: onSaveInstanceState()
03-24 20:06:42.226 21691-21691/com.hzw.tapp I/MainActivity: onStop()

从Log日志可以说明,onSaveInstanceState方法是在onStop之前调用。
2、当Activity异常终止或系统配置发生改变,回调以下:
在设置configChanges时,需注意还要加上screenSize这个属性,否则会不起作用,不会调用
onConfigurationChanged方法。

03-24 13:25:32.655 2499-2499/com.hzw.tapp I/MainActivity: onPause()
03-24 13:25:32.655 2499-2499/com.hzw.tapp I/MainActivity: onSaveInstanceState()
03-24 13:25:32.655 2499-2499/com.hzw.tapp I/MainActivity: onStop()
03-24 13:25:32.655 2499-2499/com.hzw.tapp I/MainActivity: onDestroy()
------------------------------
03-24 13:25:32.675 2499-2499/com.hzw.tapp I/MainActivity: onCreate()
03-24 13:25:32.675 2499-2499/com.hzw.tapp I/MainActivity: onStart()
03-24 13:25:32.675 2499-2499/com.hzw.tapp I/MainActivity: onRestoreInstanceState()
03-24 13:25:32.675 2499-2499/com.hzw.tapp I/MainActivity: onResume()

从以上log日志可以得出,当系统配置改变后,Activity会被销毁,会调用onPause、onStop、onDestroy,在销毁过程中,会通过onSaveInstanceState方法中Bundle对象来保存Activity当前的状态实例,同时可以看出onSaveInstanceState调用时机是在onStop之前,和系统默认情况是一样的;Activity被销毁,同时会重建一个Activity实例,和正常启动生命周期是一样的,会调用onCreate、onStart、onResume,并且系统会调用onRestoreInstanceState和onCreate方法获取onSaveInstanceState中的Bundle对象来恢复之前的状态参数,同时也可以看出onRestoreInstanceState是在onStart之后调用的。需注意的是onRestoreInstanceState方法只有在Activity异常终止情况下才会被调用。

这里写图片描述
二、资源内存不足导致低优先级Activity被杀死
针对内存不足的情况,其数据的存储与恢复和上面的流程是一样的。Activity按照优先级从高到低,主要有三种:

  1. 前台Actvity:正在和用户交互的Activity,优先级最高
  2. 可见非前台Activity:比如Activity中弹出一个对话框,导致Activity可见但是位于后台无法与用户直接交互
  3. 后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低

当系统内存不足时,系统会按照上述优先级杀死Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。

Activity属性configChanges

上面分析了Activity异常终止或系统配置发生改变时,Activity会销毁被重新创建,如果开发中不要求重新创建,可以通过给Activity设置指定的configChanges 属性值。比如不想让Activity在横竖屏切换而重新创建,此时可以通过设置configChanges的属性值为orientation,如下:

android:configChanges="orientation"

此时在测试过程你会发现单单给android:configChanges设置为orientation是无效的,在横竖屏切换过程中依然会Activity重新创建,onConfigurationChanged方法没有被调用,此时需要再指定一个值,加上screenSize,才能防止横竖切换时Activity不会重建,如下:

android:configChanges="orientation|screenSize"
03-24 17:22:02.592 4036-4036/com.hzw.tapp D/MainActivity: onConfigurationChanged: 2
03-24 17:22:08.172 4036-4036/com.hzw.tapp D/MainActivity: onConfigurationChanged: 1
03-24 17:22:11.382 4036-4036/com.hzw.tapp D/MainActivity: onConfigurationChanged: 2

从上面的Log日志可见,Activity在横竖屏切换过程中是没有重新创建,并且也没有调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,取而代之的是系统调用了onConfigurationChanged方法,此时我们可以通过该方法做一些特殊操作。最后附上configChanges属性值:

属性值:
含义:
mcc
SIM卡唯一标识IMSI(国际移动用户标识码)中的国家代码,由三位数字组成,中国为:460 这里标识mcc代码发生了改变
mnc
SIM卡唯一标识IMSI(国际移动用户标识码)中的运营商代码,有两位数字组成,中国移动TD系统为00,中国联通为01,电信为03,此项标识mnc发生了改变
locale
设备的本地位置发生了改变,一般指的是切换了系统语言
touchscreen
触摸屏发生了改变
keyboard
键盘类型发生了改变,比如用户使用了外接键盘
keyboardHidden
键盘的可访问性发生了改变,比如用户调出了键盘
navigation
系统导航方式发生了改变
screenLayout
屏幕布局发生了改变,很可能是用户激活了另外一个显示设备
fontScale
系统字体缩放比例发生了改变,比如用户选择了个新的字号
uiMode
用户界面模式发生了改变,比如开启夜间模式-API8新添加
orientation
屏幕方向发生改变,比如旋转了手机屏幕
screenSize
当屏幕尺寸信息发生改变(当编译选项中的minSdkVersion和targeSdkVersion均低于13时不会导致Activity重启)-API13新添加
smallestScreenSize
设备的物理屏幕尺寸发生改变,这个和屏幕方向没关系,比如切换到外部显示设备-API13新添加
layoutDirection
当布局方向发生改变的时候,正常情况下无法修改布局的layoutDirection的属性-API17新添加

Android之Activity生命周期(一)

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/79680519