概述
Android的Activity组件生命周期包含正常生命周期和异常情况下的生命周期。
正常生命周期
正常情况下,Activity包含7个生命周期:
(1)onCreate:Activity正在创建,是整个Activity生命周期的第一个调用方法。在这个可以做一些子控件的初始化、加载页面布局、初始化数据等工作;
(2)onStart:Activity正在被启动,这个时候,Activity已经可见,但是在后台,还不能和用户交互,对用户来说是不可见的;
(3)onResume:Activity来到前台,用户可见可交互;
(4)onPause:Activity正在停止,很快就会调用onStop。这个时候如果手速过快,快速回到当前的Activity,那么便不会调用onStop,而是会调用onResume,当前Activity再次来到前台,变得可交互。但是这种情况一般是不可复现的。在这个方法中,不能做耗时操作,一般可以存储数据、停止动画。如果太耗时,会影响新的Activity的创建,因为只有当前Activity的onPause的执行完,新的Activity的onResume才会执行;
(5)onStop:Activity即将停止。这个时候可以进行一些稍微耗时的回收操作,但是也不能太耗时;
(6)onDestroy:Activity即将被销毁。是整个Activity生命周期的最后一个调用方法。在这个方法中,要回收和释放资源。 还有一个正常生命周期比较特殊,是Activity从后台来到前台时被调用的:
(7)onRestart:Activity正在重新启动,Activity从不可见到可见就会调用这个方法。出现调用这个方法的情况一般是用户回到桌面或者打开新的Activity后,调用了onPause和onStop之后,再回到这个Activity,就会调用onRestart。
正常情况下的生命周期就包含这七个,如下图所示:
从上图可以看出,正常生命周期是两两配对的,其中:
1️⃣onCreate和onDestroy配对,分别表示Activity的创建和销毁,只会被调用一次。
2️⃣onStart和onPause配对,根据用户操作和屏幕的点亮熄灭会被多次调用。
3️⃣onResume和onStop配对,根据用户操作和屏幕的点亮熄灭会被多次调用。
那么,用户的各种操作分别对应着Activity生命周期的那些方法呢?
(1)用户回到桌面、用户打开新的Activity:调用onPause——>onStop。这里注意,加入当前的Activity使用的主题是透明主题,那么不会调用onStop;
(2)用户回到原Activity:onRestart——>onStart——>onResume;
(3)点击返回按钮:调用当前Activity的onPause——>onStop——>onDestroy
异常情况的生命名周期
异常情况下的生命周期包括两种,1️⃣是系统资源配置变化,导致Activity销毁和重建;2️⃣是系统内存不足,导致Activity被回收,这种情况和Activity的优先级有关。
系统资源配置变化
某些系统资源配置变化会导致Activity被回收,然后重建。这里以屏幕旋转为例(当然也可以通过设置,阻止这种Activity的销毁和重建),系统配置发生了变化,Activity随之被销毁和重建。这个过程和正常的Activity的生命周期就发生了改变,Activity的onPause——>onStop——>onDestroy均会被调用,并且系统还会产生一个回调onSaveInstanceState(),这个方法用于保存之前Activity的一些状态信息,例如EditText中输入的文字,我们也可以在这个方法中手动的保存一些信息。需要注意的是onSaveInstanceState()方法调用的时机确定在onStop之前,但是和onPause的前后关系不确定。
其后,Activity会进行重建,在Activity调用onStart方法之后,会调用onRestoreInstanceState(),这个方法接收来自onSaveInstanceState()传递过来的一个bundle对象,该对象包含了之前Activity的信息。这个bundle对象会同时传递给onCreate()函数。因此,可以在onCreate函数和onRestoreInstanceState中取得数据,进行恢复。但是要注意的是,在onCreate中这个bundle对象有可能为空,正常生命周期这个bundle对象就为空,因此如果要在onCreate中恢复数据,一定要判断bundle对象是否为空,而在onRestoreInstanceState中则不用判空,因为产生onRestoreInstanceState这个回调,说明已经是异常生命周期。对应生命周期如下图所示:
我们模拟一下,这个过程:
package com.example.daihao.chap1test;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.Printer;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText mEditText;
private String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"onCreate");
setContentView(R.layout.activity_main);
mEditText = findViewById(R.id.EV);
if (savedInstanceState != null){
// 获取手动保存的数据
String testStr = savedInstanceState.getString("TestData");
Log.d("MainActivity","oncreate获取的手动存储的数据:" + testStr);
}
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG,"onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG,"onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG,"onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG,"onDestroy");
}
/**
* 当系统资源发生变化,activity需要销毁重建时,调用此函数保存保存当前屏幕中数据
* @param outState
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d("MainActivity","onSaveInstanceState存储数据:");
// 手动保存数据
outState.putString("TestData","测试数据");
}
/**
* 接收来自onSaveInstanceState传入的存有数据的bundle对象,在新的activity创建的时候恢复
* @param savedInstanceState
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// 获取手动保存的数据
String testStr = savedInstanceState.getString("TestData");
Log.d("MainActivity","onRestoreInstanceState获取的手动存储的数据:" + testStr);
}
}
在页面中,我们加入了一个EditText控件。我们旋转屏幕之后,可以发现系统自动为我们保存了输入框中的数据:
而观察Activity的生命周期,如下:
内存不足导致Activity被回收
内存资源不足时,Activity会按照从低到高的顺序被回收,其中包含三种优先级:
(1)前台Activity,可见的、可交互的Activity,优先级最高,最后被回收;
(2)非前台可见Activity,例如位于弹窗后,可以看见的Activity,优先级次之;
(3)后台Activity,不可见,并且暂停的Activity,优先级最低,最先被回收。
系统会按照优先级最低的先回收,同时调用onSaveInstanceState保存数据,当Activity再次被创建的时候,通过onRestoreInstanceState获取数据并恢复。
防止系统配置变化引起Activity异常生命周期
能够引起Activity异常生命周期的配置很多,要阻止这种变化,需要给Activity指定configChanges属性,目前常用的属性包括locale(一般是切换系统语音引起)、orientation(屏幕旋转)、keyboardHidden(键盘访问性发生变化)。 假如我们要同时阻止locale(一般是切换系统语音引起)、orientation(屏幕旋转)引起的Activity异常生命周期,就要在AndroidMeniFest.xml中加入Activity声明:
这个时候,旋转屏幕并不是调用onSaveInstanceState保存数据和onRestoreInstanceState获取数据并恢复。