Activity生命周期

作者: 老勇 | 来源:发表于2016-09-18 14:48 被阅读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;

    /**

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

    /**

    • 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里设置的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

    相关文章

      网友评论

      本文标题:Activity生命周期

      本文链接:https://www.haomeiwen.com/subject/ysmwettx.html