Android官方文档和其他不少资料都对Activity生命周期进行了详细介绍,结合资料本文将对Activity生命周期进行一次总结。
Activity是由Activity栈进管理,当来到一个新的Activity后,此Activity将被加入到Activity栈顶,之前的Activity位于此Activity底部。Acitivity一般意义上有四种状态:
1.当Activity位于栈顶时,此时正好处于屏幕最前方,此时处于运行状态;
2.当Activity失去了焦点但仍然对用户可见(如栈顶的Activity是透明的或者栈顶Activity并不是铺满整个手机屏幕),此时处于暂停状态;
3.当Activity被其他Activity完全遮挡,此时此Activity对用户不可见,此时处于停止状态;
4.当Activity由于人为或系统原因(如低内存等)被销毁,此时处于销毁状态;
在每个不同的状态阶段,Adnroid系统对Activity内相应的方法进行了回调。因此,我们在程序中写Activity时,一般都是继承Activity类并重写相应的回调方法。
我们来看一下这一张经典的生命周期流程图:
先贴一张来自官方文档(http://developer.android.com/reference/android/app/Activity.html
)的图,相信大家都看到过。
<pre><code>
public class Activity extends ApplicationContext {
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}</pre></code>
相信不少朋友也已经看过这个流程图了,也基本了解了Activity生命周期的几个过程,我们就来说一说这几个过程。
(结论都是在Android6.0系统上亲测)
1、当一个Activity正常启动时:onCreate
->onStart
->onResume
-> onWindowFocusChanged
,Activity进入运行状态。
<pre><code>
09-18 10:57:01.264 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onCreate called.
09-18 10:57:01.274 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStart called.
09-18 10:57:01.274 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onResume called.
09-18 10:57:01.314 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.</pre></code>
2、当前Activity被其他Activity完全覆盖其上:系统会调用onPause
->onWindowFocusChanged
->onSaveInstanceState
->onStop
方法,暂停当前Activity的执行。
<pre><code>
09-18 11:01:18.654 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
09-18 11:01:18.664 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
09-18 11:01:19.014 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onSaveInstanceState called. put param: 1
09-18 11:01:19.014 9686-9686/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStop called.
</pre></code>
3、当前Activity被对话框遮挡失去焦点(没有完全遮挡),系统会调用onWindowFocusChanged
(没有调用其他声生命周期方法)
<pre><code>
09-18 11:07:01.094 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
</pre></code>
4、修改OrientationActivity
在AndroidManifest.xml
中的配置,将android:theme属性设置为@android:style/Theme.Dialog
,然后再点击LifeCycleActivity
中的按钮,跳转行为就变为了OrientationActivity
覆盖到LifeCycleActivity
之上了,(和第3点有区别)此时调用的方法为:onPause
->onWindowFocusChanged
->onSaveInstanceState
<pre><code>
01-19 00:00:15.170 17422-17422/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
01-19 00:00:15.180 17422-17422/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
01-19 00:00:15.510 17422-17422/xiaoyong68.com.lifecycle I/LifeCycleActivity: onSaveInstanceState called. put param: 1
</pre></code>
5、当前Activity正处于运行状态时按home键回到后台:onWindowFocusChanged
->onPause
->onSaveInstanceState
->onStop
<pre><code>
09-18 11:25:02.089 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
09-18 11:25:02.089 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
09-18 11:25:02.099 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onSaveInstanceState called. put param: 1
09-18 11:25:02.099 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStop called.
</pre></code>
6、当前Activity正处于运行状态时锁屏:onPause
->onSaveInstanceState
->onStop
->onWindowFocusChanged
<pre><code>
09-18 11:27:45.199 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
09-18 11:27:45.229 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onSaveInstanceState called. put param: 1
09-18 11:27:45.229 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStop called.
09-18 11:27:46.149 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.</pre></code>
7、当解锁屏幕Activity处于完全可见状态(或者从后台、从另外一个Activity跳转回到Activity):onRestart
->onStart
->onResume
->onWindowFocusChanged
<pre><code>09-18 11:36:37.739 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onRestart called.
09-18 11:36:37.739 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStart called.
09-18 11:36:37.739 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onResume called.
09-18 11:36:37.849 13787-13787/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.</pre></code>
8、(1)用户进行横竖屏切换,当没有在AndroidManifest.xml
中添加android:configChanges="orientation|screenSize"
这句,将不会调用onConfigurationChanged
方法:onPause
->onSaveInstanceState
->onStop
->onDestory
->onCreate
->onStart
->onRestoreInstanceState
->onResume
->onWindowFocusChanged
<pre><code>
01-18 22:07:58.290 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
01-18 22:07:58.290 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onSaveInstanceState called. put param: 1
01-18 22:07:58.290 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStop called.
01-18 22:07:58.290 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onDestory called.
01-18 22:07:58.340 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onCreate called.
01-18 22:07:58.360 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStart called.
01-18 22:07:58.360 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onRestoreInstanceState called. get param: 1
01-18 22:07:58.360 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onResume called.
01-18 22:07:58.400 19381-19381/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
</pre></code>
(2)如果在AndroidManifest.xml
中添加android:configChanges="orientation|screenSize"
这句,只会调用onConfigurationChanged
方法,不会调用其他生命周期方法:onConfigurationChanged
<pre><code>
01-18 22:18:56.300 29640-29640/xiaoyong68.com.lifecycle I/OrientationActivity: onConfigurationChanged called.
</pre></code>
8当Activity按back键正常退出:onPause
->onWindowFocusChanged
->onStop
->onDestory
<pre><code>
01-18 23:22:06.120 29640-29640/xiaoyong68.com.lifecycle I/LifeCycleActivity: onPause called.
01-18 23:22:06.140 29640-29640/xiaoyong68.com.lifecycle I/LifeCycleActivity: onWindowFocusChanged called.
01-18 23:22:06.140 29640-29640/xiaoyong68.com.lifecycle I/LifeCycleActivity: onStop called.
01-18 23:22:06.140 29640-29640/xiaoyong68.com.lifecycle I/LifeCycleActivity: onDestory called.
</pre></code>
下面我们就结合实例,来演示一下生命周期的几个过程的详细情况。我们新建一个名为lifecycle的项目,创建一个名为LifeCycleActivity的Activity,如下:
<pre><code>
package xiaoyong68.com.lifecycle;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
/**
- Activity生命周期测试
*/
public class LifeCycleActivity extends Activity {
private static final String TAG = "LifeCycleActivity";
private Context context = this;
private int param = 1;
//Activity创建时被调用
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate called.");
setContentView(R.layout.activity_lifecycle);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, OrientationActivity.class);
startActivity(intent);
// showDialog();
}
});
}
private void showDialog(){
/* @setIcon 设置对话框图标
* @setTitle 设置对话框标题
* @setMessage 设置对话框消息提示
* setXXX方法返回Dialog对象,因此可以链式设置属性
*/
final AlertDialog.Builder normalDialog =
new AlertDialog.Builder(LifeCycleActivity.this);
normalDialog.setTitle("我是一个普通Dialog");
normalDialog.setMessage("你要点击哪一个按钮呢?");
normalDialog.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//...To-do
}
});
normalDialog.setNegativeButton("关闭",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//...To-do
}
});
// 显示
normalDialog.show();
}
//Activity创建或者从后台重新回到前台时被调用
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart called.");
}
//Activity从后台重新回到前台时被调用
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart called.");
}
//Activity创建或者从被覆盖、后台重新回到前台时被调用
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume called.");
}
//Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.i(TAG, "onWindowFocusChanged called.");
}
//Activity被覆盖到下面或者锁屏时被调用
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause called.");
//有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据
}
//退出当前Activity或者跳转到新Activity时被调用
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop called.");
}
//退出当前Activity时被调用,调用之后Activity就结束了
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestory called.");
}
/**
* Activity被系统杀死时被调用.
* 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死.
* 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态.
* 在onPause之前被调用.
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("param", param);
Log.i(TAG, "onSaveInstanceState called. put param: " + param);
super.onSaveInstanceState(outState);
}
/**
* Activity被系统杀死后再重建时被调用.
* 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity.
* 这两种情况下onRestoreInstanceState都会被调用,在onStart之后.
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
param = savedInstanceState.getInt("param");
Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
super.onRestoreInstanceState(savedInstanceState);
}
}
</code></pre>
大家注意到,除了几个常见的方法外,我们还添加了onWindowFocusChanged
、onSaveInstanceState
、onRestoreInstanceState
方法:
1.onWindowFocusChanged
方法:在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;当前Activity被其他Activity覆盖;当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。以上几种情况都会调用onWindowFocusChanged
,并且当Activity被创建时是在onResume
之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause
之后被调用,如图所示:
这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate
中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged
里获取;
2.onSaveInstanceState
:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;(2)在用户改变屏幕方向时,此方法会被调用;(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState
的调用顺序是在onPause
之前。
3.onRestoreInstanceState
:
(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;
(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState
的调用顺序是在onStart之后。
后面还会有一篇文章专门描述这3个方法应用场景。
接下来介绍一下关于Activity屏幕方向的相关知识。
我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:
1.指定为竖屏:在AndroidManifest.xml
中对指定的Activity设置android:screenOrientation="portrait"
,或者在onCreate
方法中指定:
<pre><code>
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //竖屏
</pre></code>
2.指定为横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="landscape",或者在onCreate方法中指定:
<pre><code>
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏 </pre></code>
为应用中的Activity设置特定的方向是经常用到的办法,可以为我们省去不少不必要的麻烦。不过,我们今天讲的是屏幕方向改变时的生命周期,所以我们并不采用固定屏幕方向这种办法。
下面我们就结合实例讲解一下屏幕转换的生命周期,我们新建一个Activity命名为OrientationActivity,如下:
<pre><code>
package xiaoyong68.com.lifecycle;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
/**
- Activity生命周期测试
*/
public class OrientationActivity extends Activity {
private static final String TAG = "OrientationActivity";
private int param = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_orientation);
Log.i(TAG, "onCreate called.");
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart called.");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart called.");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume called.");
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause called.");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop called.");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestory called.");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("param", param);
Log.i(TAG, "onSaveInstanceState called. put param: " + param);
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
param = savedInstanceState.getInt("param");
Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
super.onRestoreInstanceState(savedInstanceState);
}
//当指定了android:configChanges="orientation|screenSize"后,方向改变时onConfigurationChanged被调用
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i(TAG, "onConfigurationChanged called.");
switch (newConfig.orientation) {
case Configuration.ORIENTATION_PORTRAIT:
// setContentView(R.layout.orientation_portrait);
Log.i(TAG, "1");
break;
case Configuration.ORIENTATION_LANDSCAPE:
Log.i(TAG, "2");
break;
}
}
}
</pre></code>
Activity的生命周期与程序的健壮性有着密不可分的关系,希望朋友们能够认真体会、熟练应用。
小插曲:在调试的生活碰到一个奇怪的问题:
onConfigurationChanged
未被调用???
根据正常认知,在AndroidManifest.xml
中设置Android:configChanges="orientation“
,然后在Java代码中重写onConfigurationChanged
,即不会重复Activity生命周期方法,而是调用onConfigurationChanged
。
然而今天这种做法没有效果,什么原因呢。
原来,自从Android 3.2(API 13),screen size也开始跟着设备的横竖切换而改变。
所以,在AndroidManifest.xml
里设置的MiniSdkVersion
和TargetSdkVersion
属性大于等于13的情况下,
如果你想阻止程序在运行时重新加载Activity,除了设置”orientation“
,你还必须设置"ScreenSize"
。
解决方法:AndroidManifest.xml
中设置android:configChanges="orientation|screenSize“
4.2又碰到同样的问题了,还得再加上个"layoutDirection"
备注:
Activity的onSaveInstanceState()
和 onRestoreInstanceState()
并不是生命周期方法,它们不同于onCreate()
、onPause()
等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState()
才会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()
就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()
只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
另外,当屏幕的方向发生了改变,Activity会被摧毁并且被重新创建,如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的onSaveInstanceState()
和onRestoreInstanceState()
方法,如下:
<pre><code>
public class PreferencesActivity extends Activity {
private String name;
protected void
onRestoreInstanceState(BundlesavedInstanceState) {
name = savedInstanceState.getString("name");//被重新创建后恢复缓存的数据
super.onRestoreInstanceState(savedInstanceState);
}
protected void onSaveInstanceState(BundleoutState) {
outState.putString("name", "liming");//被摧毁前缓存一些数据
super.onSaveInstanceState(outState);
}
}
</pre></code>
demo下载地址:https://github.com/xiaoyong68/blog_TestCode_save.git