前言
对于Activity的生命周期大家都很熟悉,有onCreate、onStart、onResume、onPause、onStop、onDestroy这几个方法。
本文将讲述关于Activity生命周期更深层次的知识(部分内容从源码角度解读),并且讲述一下不常被提及,却十分重要的概念。
生命周期概述
几种生命周期
(1)onCreate:表是Activity正在创建,是生命周期的第一个方法,主要进行加载布局、初始化Window等操作。
(2)onRestart:表示Activity正在重新启动,当Activity由不可见变为可见时调用。这一行为主要是由用户触发(Back或切换应用等操作)。
(3)onStart:表示Activity正在启动,这时Activity已经可见了,只是还没有出现在前台,无法和用户交互。
(4)onResume:表示Activity已经可见了,这时Activity已经可见了,并且出现在了前台,可以和用户进行交互。onStart和onResume都表示Activity已经可见了,但是onResume时,Activity才会显示到前台,并且可以进行交互。
(5)onPause:表示Activity正在暂停,后面通常会调用onStop方法(部分特例请看下文)。onPause可以做一些数据暂存、动画关闭等操作,不能进行耗时操作,因为下一个Activity启动前,必须要当前Activity已经Pause后才能显示(具体原因请看下文),耗时操作会影响到下一个页面的显示。
(6)onStop:表示Activity正在停止,可以进行一些略重量级的回收工作,但也不能太耗时。
(7)onDestroy:表示Activity正在被销毁,是Activity生命周期的最后一个回调,可以进行最终的资源释放(unRegister或unBind)。
常规生命周期切换
(1)新建一个Activity,新Activity的生命周期回调如下:onCreate->onStart->onResume。
(2)新建一个Activity,原Activity的生命周期回调如下:onPause->onStop(部分情况下不调用)。这里需要需要注意,当新页面使用透明、Dialog主题时,原页面并不会调用onPause方法。
(3)当用户Back时,原Activity的生命周期回调如下:onRestart->onStart->onResume。
(4)当用户Back时,当前Activity的生命周期回调如下:onPause->onStop->onDestroy。
(5)Activity被回收后重新打开时,生命周期回调同(1),但是系统会自动进行一些数据、状态的保存和恢复工作。
何时生命周期不回调onStop方法?
当原页面未被完全覆盖时,即启动的页面为Dialog或透明主题,原页面不会回调onStop方法。
设置Dialog主题
Activity
<activity
android:name=".Main2Activity"
android:theme="@android:style/Theme.Dialog"/>
AppCompatActivity
<activity
android:name=".Main2Activity"
android:theme="@style/Theme.AppCompat.Dialog"/>
设置透明主题
Activity
<activity
android:name=".Main2Activity"
android:theme="@android:style/Theme.Translucent" />
AppCompatActivity
<style name="MyTranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">#00000000</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<activity
android:name=".Main2Activity"
android:theme="@style/MyTranslucentTheme" />
实例验证
依据以上方法设置ActivityB主题,验证log如下:
2019-05-12 00:30:59.526 4740-4740/com.gcc.demo D/ActivityA: onCreate:
2019-05-12 00:30:59.527 4740-4740/com.gcc.demo D/ActivityA: onStart:
2019-05-12 00:30:59.529 4740-4740/com.gcc.demo D/ActivityA: onResume:
2019-05-12 00:31:01.706 4740-4740/com.gcc.demo D/ActivityA: onClick: +++++++++++++++++++启动ActivityB
2019-05-12 00:31:01.718 4740-4740/com.gcc.demo D/ActivityA: onPause:
2019-05-12 00:31:01.760 4740-4740/com.gcc.demo D/ActivityB: onCreate:
2019-05-12 00:31:01.761 4740-4740/com.gcc.demo D/ActivityB: onStart:
2019-05-12 00:31:01.766 4740-4740/com.gcc.demo D/ActivityB: onResume:
新页面的onResume和原页面的onPause谁先调用?
前文说到新页面调用onResume前,原页面的onPause必须先调用,具体原因我们从源码中获取。下面贴一段Android9.0中ActivityStack类的resumeTopActivityInnerLocked方法的源码:
If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity to be paused, while at the same time resuming the new resume activity only if the previous activity can't go into Pip since we want to give Pip activities a chance toenter Pip before resuming the next activity.
从上面这段源码以及相应注释可以看出,如果没有设置RESUME_WHILE_PAUSING这个Flag,那么新页面调用onResume时,原页面的onPause必须先调用
。
系统配置发生改变时Activity被重新创建
Activity重建时的生命周期
当系统的配置发生改变时(例如手机横竖屏切换、系统语言切换等),Activity会被重新创建。此时Activity生命周期和创建时一样,只不过这时候Activity会调用onSaveInstanceState
、onRestoreInstanceState
这一组方法来进行页面数据的缓存以及恢复(正常启动Activity时不会触发该组方法)。
PS:Activity的数据缓存与恢复可以看本人另一篇文章
Android如何应对内存回收机制
如何避免配置修改后Activity被重建
如果不想系统配置修改后重启Activity,也可以给configChanges添加不需要重启的指定配置项。例如,横竖屏、语言变化时不想重启Activity,可这样写:
<activity
android:name=".Main2Activity"
android:configChanges="locale|orientation" />
PS:configChanges详细配置请看本人另一篇文章
Android修改系统设置后Activity被重新创建
Activity被系统回收后再次重建
当系统内存不足时,Android系统会自动回收一些低优先级的进程,或者回收一些已被停止的后台Activity。
Activity优先级
Activity优先级如下,由高到低:
- 前台Activity--正在和用户交互的Activity。高优先级。
- 可见但不可交互Activity--上层页面为Dialog、透明主题,即已Pause但未Stop的页面。中优先级。
- 后台Activity--已Stop的Activity。低优先级。
Activity重建时的生命周期
Activity被重建时,Activity生命周期和新建时一样,只不过这时候Activity也会调用onSaveInstanceState
、onRestoreInstanceState
这一组方法来进行页面数据的缓存以及恢复(正常启动Activity时不会触发该组方法)。
PS:如何处理内存被回收可以看本人另一篇文章
Android如何应对内存回收机制
NewIntent状态下的生命周期
什么情况下会触发onNewIntent回调方法?
这个问题我们从源码中求解。下面贴一段Android9.0中Activity类的startActivityIfNeeded方法的头注释:
if you are using the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag, or singleTask or singleTop and the activity that handles <var>intent</var> is the same as your currently running activity , then a new instance is not needed.
从注释中可以看出,在不需要创建一个新的Activity实例时,生命周期会回调onNewIntent方法。不需要创建新Activity实例主要有这两种情况:
(1)启动模式为singleTask,且栈内已存在待创建实例;
(2)启动模式为singleTop,且栈顶就是待创建实例。
触发onNewIntent方法时,Activity生命周期是怎样的?
在singleTask和singleTop启动模式下,启动一个已存在的Activity(PS:只看在栈顶的情况),该Activity的生命周期会如何回调呢?
回调的时序应该是onPause->onNewIntent->onResume。
触发onNewIntent回调的注意事项
在回调onNewIntent方法时,需要注意将onNewIntent传入的intent替换为当前Intent,否则新Intent附加值并不会被传递给页面。需要调用如下方法: