深入理解Activity的生命周期(必备)

目录

 

前言

基本认知

典型情况下的生命周期分析:

典型情况下的生命周期的总结:

异常情况下的生命周期分析:

onSaveInstanceState源码分析:

onSaveInstanceState工作过程图:

总结:

onRestoreInstanceState源码分析:

onRestoreInstanceState工作过程图:

总结:

configChanges详细属性

locale(常用)

keyboardHidden

orientation

screenSize

onConfigurationChanged部分源码分析:

完结:


前言

 

  • Activity 作为四大组件之一,是使用最为频繁的一种组件
  • Activity在异常情况下的生命周期十分微妙
  • 让你面试的时候不只是会说onCreat→onRestart→onStart→onResume→onPause→onStop→onDestroy
  • 文章冗长,建议收藏

基本认知

  1. 典型情况下的生命周期是什么,它们又是怎样切换的?
  2. 异常情况下的生命周期有哪些特殊的方法?
  3. 异常情况都是有哪些?

让我们带着这些问题继续向下研究:

典型情况下的生命周期分析:

正常情况下,Activity的生命周期的切换过程如下图:

针对上图,我们真实的测试一下切换过程:

示例1:两个标准的Activity,MainActivity(launch)和NextActivity,代码如下:

MainActivity:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG, "onCreate: ");
        initView();

    }

    private void initView() {
        findViewById(R.id.to_next).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, NextActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "onRestart: ");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart: " );
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause: " );
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop: " );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: " );
    }


}

NextActivity 

public class NextActivity extends AppCompatActivity {
    private static final String TAG = "NextActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_next);
        Log.e(TAG, "onCreate: " );
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "onRestart: ");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart: " );
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause: " );
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop: " );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: " );
    }

}
manifest
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:theme="@style/Transparent"
            android:name=".NextActivity"></activity>
    </application>

代码执行结果

  • 打开MainActivity

  • 退出MainActivity

 

  • 从MianActivity跳转到NextActivity

  • 执行物理返回键

  • 锁屏

  • 解锁

  • 长按Home键杀掉进程

特例1:将NextActivity主题设置为透明:重新执行上述操作

从MianActivity跳转到NextActivity时   MainActivity没有执行onStop

执行物理返回键     MianActivity只是执行onResume

 

 

典型情况下的生命周期的总结:

  1. 针对一个特定的Activity,第一次启动,回调如下:onCreat→onStart→onResume
  2. 当用户打开新的Activity或者切换到桌面的时候,回调如下:onPause→onStop  如果新的Activity采用透明主题,那么当前Activity不会回调onStop.
  3. 当用户再次返回当前Activity的时,回调如下:onRestart→onStart→onResume  如果前一Activity采用透明主题,当前Activity只会执行onResume ,不会执行onRestart 和onStart
  4. 当用户按back键回退时,回调如下:onPause→onStop→onDestroy
  5. 从生命周期来看,onCreat和onDestroy是成对的,分别标识着Activity的创建和销毁,并且只调用一次;onStart和onStop是配对的,分别标识着Activity的可见和不可见,可能会被多次调用;onResume和onPause是配对的,分别标识着Activity是否位于前台。

异常情况下的生命周期分析:

异常情况主要分为两种:

  1. 资源相关的系统配置发生改变导致Activity被杀死并重新创建
  2. 资源内存不足导致低优先级的Activity被杀死

在默认情况下,如果我们的Activity不做特殊处理,那么当系统配置发生变化改变后,Acticity就会被销毁重建。

示例2:在上述示例1中添加下面这两个protrcted方法:

  @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("outStatePut","test");
        Log.e(TAG, "protected onSaveInstanceState: " );
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.e(TAG, "onRestoreInstanceState: " );
    }

 

切换横竖屏结果如下:

onSaveInstanceState源码分析:

(1)保存数据

//第一步 事件委托
 private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
        r.state = new Bundle();
        r.state.setAllowFds(false);
        if (r.isPersistable()) {//判断是否数据永久性存储
            r.persistentState = new PersistableBundle();
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                    r.persistentState);
        } else {
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
        }
    }



//第二步  
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
    activity.performSaveInstanceState(outState);
}
  final void performSaveInstanceState(Bundle outState) {
        onSaveInstanceState(outState);  // 1 保存页面信息
        saveManagedDialogs(outState);   // 2 保存对话框的引用及相关参数
        mActivityTransitionState.saveState(outState);  //3 保存页面跳转信息
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}


//第三步  
   protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());//保存Window信息
        Parcelable p = mFragments.saveAllState();//保存Fragment信息
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

//第四步  遍历向下分发委托

 void dispatchActivitySaveInstanceState(Activity activity, Bundle outState) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
             ((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity,
                        outState); //下发
            }
        }
    }

onSaveInstanceState工作过程图:

总结:

  1. onSaveInstanceState 调用的时机在onStop之前
  2. 系统默认保存当前Activity的视图结构
  3. 保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreat方法

(2)取数据

分为两种情况:

1)

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

   
        if (null!=savedInstanceState){
            String test =savedInstanceState.getString("outStatePut");

        }
    }

2)

   @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String test =savedInstanceState.getString("outStatePut");

        Log.e(TAG, "onRestoreInstanceState: " );
    }

onRestoreInstanceState源码分析:

//第一步   Activity启动调用
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      ActivityThread.performLaunchActivity(" + r + ")");

       ...无关代码省略
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                          //保证有值才会调用
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                     return activity;
    }

//第二步
  public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
        activity.performRestoreInstanceState(savedInstanceState);
    }
//第三步
    final void performRestoreInstanceState(Bundle savedInstanceState) {
        onRestoreInstanceState(savedInstanceState);
        restoreManagedDialogs(savedInstanceState);
    }
//第四步

/** 此方法在{@link #onStart}之后调用,此时活动正在从先前保存的状态重新初始化,在{@link #onStart}和* {@link #onPostCreate}之间调用。 */

 protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

onRestoreInstanceState工作过程图:

 

有兴趣的伙计,自己看一下onCreat源码,与onRestoreInstanceState类型

总结:

  1. onRestoreInstanceState 调用的时机在onStart之后
  2. onRestoreInstanceState一旦被调用,其参数Bundle一定是有值的(源码进行了非null判断)
  3. onCreat 正常调用 Bundle为null ,所以如果要在此方法内获取budle要进行非null判断

configChanges:

当系统配置发生变化后,Activity会被重新创建,那么有没有办法不重新创建呢?答案是有的

我们可以给Activity指定configChanges属性

将MainActivity的configChanges设置为screenSize|orientation    

<activity android:name=".MainActivity"

           android:configChanges="screenSize|orientation">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

横竖屏切换就不会销毁重建,只会执行onConfigurationChanged

configChanges详细属性

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

 

onConfigurationChanged部分源码分析:

  //步骤一:ActivityThread收到消息
case ACTIVITY_CONFIGURATION_CHANGED:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
                    handleActivityConfigurationChanged((ActivityConfigChangeData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

  //步骤二:
 final void handleActivityConfigurationChanged(ActivityConfigChangeData data) {
        ActivityClientRecord r = mActivities.get(data.activityToken);
        if (r == null || r.activity == null) {
            return;
        }

        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                + r.activityInfo.name);

        r.tmpConfig.setTo(mCompatConfiguration);
        if (data.overrideConfig != null) {
            r.overrideConfig = data.overrideConfig;
            r.tmpConfig.updateFrom(data.overrideConfig);
        }
        performConfigurationChanged(r.activity, r.tmpConfig);

        freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));

        mSomeActivitiesChanged = true;
    }


//步骤三

private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {
  
        Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
        if (activity != null) {
            activity.mCalled = false;
        }
        boolean shouldChangeConfig = false;
        if ((activity == null) || (activity.mCurrentConfig == null)) {
            shouldChangeConfig = true;
        } else {

       //如果新配置与此活动的配置相同,那就不用调用onConfigurationChanged

            int diff = activity.mCurrentConfig.diff(config);
            if (diff != 0) {
                // If this activity doesn't handle any of the config changes
                // then don't bother calling onConfigurationChanged as we're
                // going to destroy it.
                if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
                    shouldChangeConfig = true;
                }
            }
        }

        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb
                + ": shouldChangeConfig=" + shouldChangeConfig);
        if (shouldChangeConfig) {
// 步骤4
            cb.onConfigurationChanged(config);

            if (activity != null) {
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                            "Activity " + activity.getLocalClassName() +
                        " did not call through to super.onConfigurationChanged()");
                }
                activity.mConfigChangeFlags = 0;
                activity.mCurrentConfig = new Configuration(config);
            }
        }
    }

完结:

 - 如果您觉得帮助了您给个star ,您的支持是我的动力!!!

 - 由于本人研究源码有限,如有错误,欢迎指出

 - 如果您有问题或者想加入Android家庭,请加qq群:659014357

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值