Android基础知识

Activity生命周期

2016-09-18  本文已影响65人  老勇

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
)的图,相信大家都看到过。

Activity生命周期.png

<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、修改OrientationActivityAndroidManifest.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;

/**

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>
大家注意到,除了几个常见的方法外,我们还添加了onWindowFocusChangedonSaveInstanceStateonRestoreInstanceState方法:
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;

/**

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里设置的MiniSdkVersionTargetSdkVersion属性大于等于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

上一篇下一篇

猜你喜欢

热点阅读