Activity生命周期&横竖屏切换(代码验证)

970 阅读8分钟

老生常谈的activity 7大方法(onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart)和4种状态(Active、Paused、Stopped、Dead)这些都好记,但是多个页面之间切换,弹窗(AlertDialog),activity弹窗(半遮挡,全遮挡),锁屏,解屏,横竖屏切换生命周期变化等这些场景参杂一起还是有点蒙。本文就将以上列的几种场景在代码中在验证下,加深理解,加深印象。

activity生命周期

一.页面切换,弹窗引起的生命周期变化问题。

1.新启动一个Activity

2021-08-03 16:03:02.261 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onCreate
2021-08-03 16:03:02.431 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:03:02.435 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onResume
-----jump secondActivity--------

2021-08-03 16:03:26.400 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onPause

2021-08-03 16:03:26.432 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onCreate
2021-08-03 16:03:26.483 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onStart
2021-08-03 16:03:26.485 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onResume

2021-08-03 16:03:26.782 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onStop

2021-08-03 16:03:26.784 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@eb73172, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@53cf9c3, 2131230770=android.view.AbsSavedState$1@eb73172, 2131230776=android.view.AbsSavedState$1@eb73172, 2131230843=android.view.AbsSavedState$1@eb73172, 2131231130=com.google.android.material.button.MaterialButton$SavedState@ee1f240, 2131231131=android.view.AbsSavedState$1@eb73172, 2131231132=com.google.android.material.button.MaterialButton$SavedState@b83d579, 2131231133=com.google.android.material.button.MaterialButton$SavedState@6c2f2be, 2131231134=android.view.AbsSavedState$1@eb73172}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@3eb6f1f}]
-----锁屏-------
2021-08-03 16:04:26.542 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onPause
2021-08-03 16:04:26.616 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onStop
2021-08-03 16:04:26.628 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@eb73172, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@85bab1, 2131230770=android.view.AbsSavedState$1@eb73172, 2131230776=android.view.AbsSavedState$1@eb73172, 2131230843=android.view.AbsSavedState$1@eb73172}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@db89b96}]
------解屏-----
2021-08-03 16:05:55.354 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onRestart
2021-08-03 16:05:55.355 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onStart
2021-08-03 16:05:55.356 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onResume
------返回上一页mainActivity--物理返回键-----
2021-08-03 16:06:35.619 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onPause
2021-08-03 16:06:35.688 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onRestart
2021-08-03 16:06:35.698 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:06:35.703 29605-29605/com.example.myfirstproject D/MainActivity-TEST: onResume
2021-08-03 16:06:36.000 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onStop
2021-08-03 16:06:36.001 29605-29605/com.example.myfirstproject D/SecondActivity-TEST: onDestroy

以上就是标准的生命周期变化,需要注意下第一个Activity的生命周期onPause和onStop的执行时机。onStop是在第二个Activity onResume后才执行。

2.开启AlertDialog弹窗

当前Activity生命周期无变化。

也好理解,AlertDialog只是通过AddView添加进了当前Activity布局中,所以这个AlertDialog还是在当前Activity里。

3.启动一个Theme是全遮挡的dialog主题的Activity

2021-08-03 16:18:07.207 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onCreate
2021-08-03 16:18:07.381 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:18:07.385 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onResume
------------打开dialogActivity--------
2021-08-03 16:18:29.276 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onPause
2021-08-03 16:18:29.305 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onCreate
2021-08-03 16:18:29.347 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onStart
2021-08-03 16:18:29.349 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onResume
2021-08-03 16:18:29.668 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onStop
2021-08-03 16:18:29.671 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@813f26c, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@fe35035, 2131230770=android.view.AbsSavedState$1@813f26c, 2131230776=android.view.AbsSavedState$1@813f26c, 2131230843=android.view.AbsSavedState$1@813f26c, 2131231130=com.google.android.material.button.MaterialButton$SavedState@4377cca, 2131231131=android.view.AbsSavedState$1@813f26c, 2131231132=com.google.android.material.button.MaterialButton$SavedState@1e1de3b, 2131231133=com.google.android.material.button.MaterialButton$SavedState@b83c958, 2131231134=android.view.AbsSavedState$1@813f26c}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@85bab1}]
---------锁屏----------
2021-08-03 16:19:16.524 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onPause
2021-08-03 16:19:16.586 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onStop
2021-08-03 16:19:16.588 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@813f26c, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@9bfd9b3, 2131230770=android.view.AbsSavedState$1@813f26c, 2131230776=android.view.AbsSavedState$1@813f26c, 2131230843=android.view.AbsSavedState$1@813f26c}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@e766b70}]
--------解屏-----
2021-08-03 16:19:44.208 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onRestart
2021-08-03 16:19:44.209 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onStart
2021-08-03 16:19:44.210 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onResume
-------返回上一页mainActivity--物理返回键-----
2021-08-03 16:20:54.847 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onPause
2021-08-03 16:20:54.885 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onRestart
2021-08-03 16:20:54.888 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:20:54.895 31534-31534/com.example.myfirstproject D/MainActivity-TEST: onResume
2021-08-03 16:20:55.218 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onStop
2021-08-03 16:20:55.220 31534-31534/com.example.myfirstproject D/DialogActivity-TEST: onDestroy

同第一条(新启动一个Activity)比较。生命周期变化一摸一样。

4.启动一个Theme是半遮挡的dialog主题的Activity

2021-08-03 16:11:05.582 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onCreate
2021-08-03 16:11:05.750 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:11:05.754 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onResume
------------打开dialogActivity--------

2021-08-03 16:11:24.890 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onPause

2021-08-03 16:11:24.928 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onCreate
2021-08-03 16:11:24.965 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onStart
2021-08-03 16:11:24.966 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onResume
---------锁屏----------
2021-08-03 16:12:25.088 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onPause
2021-08-03 16:12:25.204 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onStop
2021-08-03 16:12:25.207 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@7d66227, 2131231103=android.view.AbsSavedState$1@7d66227}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@959dcd4}]
2021-08-03 16:12:25.212 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onStop
2021-08-03 16:12:25.216 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@7d66227, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@ee1f240, 2131230770=android.view.AbsSavedState$1@7d66227, 2131230776=android.view.AbsSavedState$1@7d66227, 2131230843=android.view.AbsSavedState$1@7d66227, 2131231130=com.google.android.material.button.MaterialButton$SavedState@b83d579, 2131231131=android.view.AbsSavedState$1@7d66227, 2131231132=com.google.android.material.button.MaterialButton$SavedState@6c2f2be, 2131231133=com.google.android.material.button.MaterialButton$SavedState@3eb6f1f, 2131231134=android.view.AbsSavedState$1@7d66227}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@813f26c}]
--------解屏-----
2021-08-03 16:13:22.628 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onRestart
2021-08-03 16:13:22.631 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 16:13:22.633 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onRestart
2021-08-03 16:13:22.633 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onStart
2021-08-03 16:13:22.635 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onResume
-------返回上一页mainActivity--物理返回键-----
2021-08-03 16:16:34.631 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onPause

2021-08-03 16:16:34.731 30559-30559/com.example.myfirstproject D/MainActivity-TEST: onResume

2021-08-03 16:16:34.790 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onStop
2021-08-03 16:16:34.792 30559-30559/com.example.myfirstproject D/DialogActivity-TEST: onDestroy

同第一条(新启动一个Activity)比较,第一个Activity只执行了onPause,并没有在第二个Activity onResume后执行onStop。在物理按键返回第一个页面时候,只执行了onResume,跟上面只执行了onPause生命周期对应的onResume.


综上归纳出:

影响生命周期变化核心是旧页面有没有被新页面完全遮挡;影响的是旧页面生命周期onStop方法是否执行。

完全遮挡,onPause-》新页面生命周期-》onStop。

半遮挡:onPause-》新页面生命周期。


二.横竖屏切换生命周期变化:

一直以来我们知道设置android:configChanges="orientation|keyboardHidden|screenSize"可以禁用横竖屏切换引起的生命周期变化,从而解决页面销毁重新创建的问题。

那接下来就通过变化android:configChanges属性设置来看横竖屏切换生命周期变化过程。

1.生命周期变化的属性设置

android:configChanges="" android:configChanges="orientation" android:configChanges="orientation|keyboardHidden" android:configChanges="screenSize"

2021-08-03 17:08:00.364 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onCreate
2021-08-03 17:08:00.532 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 17:08:00.535 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onResume
--------旋转---------
2021-08-03 17:08:41.253 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onPause
2021-08-03 17:08:41.259 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onStop
2021-08-03 17:08:41.263 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onSaveInstanceStateBundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@77b2f2d, 2131230768=androidx.appcompat.widget.Toolbar$SavedState@1a0fc62, 2131230770=android.view.AbsSavedState$1@77b2f2d, 2131230776=android.view.AbsSavedState$1@77b2f2d, 2131230843=android.view.AbsSavedState$1@77b2f2d, 2131231130=com.google.android.material.button.MaterialButton$SavedState@43d81f3, 2131231131=android.view.AbsSavedState$1@77b2f2d, 2131231132=com.google.android.material.button.MaterialButton$SavedState@ba8eb0, 2131231133=com.google.android.material.button.MaterialButton$SavedState@3089129, 2131231134=android.view.AbsSavedState$1@77b2f2d}}], androidx.lifecycle.BundlableSavedStateRegistry.key=Bundle[{}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@5967cae}]
2021-08-03 17:08:41.265 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onDestroy
2021-08-03 17:08:41.701 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onCreate
2021-08-03 17:08:41.793 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onStart
2021-08-03 17:08:41.794 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onRestoreInstanceState
2021-08-03 17:08:41.795 5717-5717/com.example.myfirstproject D/MainActivity-TEST: onResume

2.生命周期不会变化的属性设置

//android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|screenSize"

2021-08-03 17:11:47.546 6771-6771/com.example.myfirstproject D/MainActivity-TEST: onConfigurationChanged{1.0 ?mcc?mnc [zh_CN_#Hans,en_GB] ldltr sw360dp w640dp h336dp 480dpi nrml long land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1080) mAppBounds=Rect(0, 0 - 1920, 1080) mWindowingMode=fullscreen mActivityType=standard} nonFullScreen=0 suim:1 s.24}

也就是设置"orientation|screenSize"和"orientation|keyboardHidden|screenSize"都会禁用横竖屏对于生命周期变化,也就是说真正禁用横竖屏切换的是"orientation|screenSize"属性,跟keyboardHidden无瓜。

"orientation|screenSize"属性不会让页面销毁重新创建了,但是会暴露onConfigurationChanged方法给我们调用。


综上归纳出:

禁止横竖屏切换重走生命周期使用:android:configChanges="orientation|screenSize"

如果横竖屏切换重走生命周期,需要保存数据:onSaveInstanceStateBundle保存,onRestoreInstanceState恢复。