目录
前言
- Activity 作为四大组件之一,是使用最为频繁的一种组件
- Activity在异常情况下的生命周期十分微妙
- 让你面试的时候不只是会说onCreat→onRestart→onStart→onResume→onPause→onStop→onDestroy
- 文章冗长,建议收藏
基本认知
- 典型情况下的生命周期是什么,它们又是怎样切换的?
- 异常情况下的生命周期有哪些特殊的方法?
- 异常情况都是有哪些?
让我们带着这些问题继续向下研究:
典型情况下的生命周期分析:
正常情况下,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
典型情况下的生命周期的总结:
- 针对一个特定的Activity,第一次启动,回调如下:onCreat→onStart→onResume
- 当用户打开新的Activity或者切换到桌面的时候,回调如下:onPause→onStop 如果新的Activity采用透明主题,那么当前Activity不会回调onStop.
- 当用户再次返回当前Activity的时,回调如下:onRestart→onStart→onResume 如果前一Activity采用透明主题,当前Activity只会执行onResume ,不会执行onRestart 和onStart
- 当用户按back键回退时,回调如下:onPause→onStop→onDestroy
- 从生命周期来看,onCreat和onDestroy是成对的,分别标识着Activity的创建和销毁,并且只调用一次;onStart和onStop是配对的,分别标识着Activity的可见和不可见,可能会被多次调用;onResume和onPause是配对的,分别标识着Activity是否位于前台。
异常情况下的生命周期分析:
异常情况主要分为两种:
- 资源相关的系统配置发生改变导致Activity被杀死并重新创建
- 资源内存不足导致低优先级的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工作过程图:
总结:
- onSaveInstanceState 调用的时机在onStop之前
- 系统默认保存当前Activity的视图结构
- 保存的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类型
总结:
- onRestoreInstanceState 调用的时机在onStart之后
- onRestoreInstanceState一旦被调用,其参数Bundle一定是有值的(源码进行了非null判断)
- 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详细属性
属性 | 含义 |
mcc | SIM卡唯一标识IMSI(国际移动用户标识码)中的国家代码,由三位数字组成,中国为:460 这里标识mcc代码发生了改变 |
mnc | SIM卡唯一标识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