前言
對(duì)于Activity的生命周期大家都很熟悉,有onCreate停忿、onStart、onResume蚊伞、onPause席赂、onStop、onDestroy這幾個(gè)方法时迫。
本文將講述關(guān)于Activity生命周期更深層次的知識(shí)(部分內(nèi)容從源碼角度解讀)颅停,并且講述一下不常被提及,卻十分重要的概念掠拳。
生命周期概述
幾種生命周期
(1)onCreate:表是Activity正在創(chuàng)建癞揉,是生命周期的第一個(gè)方法,主要進(jìn)行加載布局溺欧、初始化Window等操作喊熟。
(2)onRestart:表示Activity正在重新啟動(dòng),當(dāng)Activity由不可見變?yōu)榭梢姇r(shí)調(diào)用胧奔。這一行為主要是由用戶觸發(fā)(Back或切換應(yīng)用等操作)逊移。
(3)onStart:表示Activity正在啟動(dòng),這時(shí)Activity已經(jīng)可見了龙填,只是還沒有出現(xiàn)在前臺(tái)胳泉,無法和用戶交互拐叉。
(4)onResume:表示Activity已經(jīng)可見了,這時(shí)Activity已經(jīng)可見了扇商,并且出現(xiàn)在了前臺(tái)凤瘦,可以和用戶進(jìn)行交互。onStart和onResume都表示Activity已經(jīng)可見了案铺,但是onResume時(shí)蔬芥,Activity才會(huì)顯示到前臺(tái),并且可以進(jìn)行交互控汉。
(5)onPause:表示Activity正在暫停笔诵,后面通常會(huì)調(diào)用onStop方法(部分特例請(qǐng)看下文)。onPause可以做一些數(shù)據(jù)暫存姑子、動(dòng)畫關(guān)閉等操作乎婿,不能進(jìn)行耗時(shí)操作,因?yàn)橄乱粋€(gè)Activity啟動(dòng)前街佑,必須要當(dāng)前Activity已經(jīng)Pause后才能顯示(具體原因請(qǐng)看下文)谢翎,耗時(shí)操作會(huì)影響到下一個(gè)頁面的顯示。
(6)onStop:表示Activity正在停止沐旨,可以進(jìn)行一些略重量級(jí)的回收工作森逮,但也不能太耗時(shí)。
(7)onDestroy:表示Activity正在被銷毀磁携,是Activity生命周期的最后一個(gè)回調(diào)褒侧,可以進(jìn)行最終的資源釋放(unRegister或unBind)。
常規(guī)生命周期切換
(1)新建一個(gè)Activity谊迄,新Activity的生命周期回調(diào)如下:onCreate->onStart->onResume璃搜。
(2)新建一個(gè)Activity,原Activity的生命周期回調(diào)如下:onPause->onStop(部分情況下不調(diào)用)鳞上。這里需要需要注意,當(dāng)新頁面使用透明吊档、Dialog主題時(shí)篙议,原頁面并不會(huì)調(diào)用onPause方法。
(3)當(dāng)用戶Back時(shí)怠硼,原Activity的生命周期回調(diào)如下:onRestart->onStart->onResume鬼贱。
(4)當(dāng)用戶Back時(shí),當(dāng)前Activity的生命周期回調(diào)如下:onPause->onStop->onDestroy香璃。
(5)Activity被回收后重新打開時(shí)这难,生命周期回調(diào)同(1),但是系統(tǒng)會(huì)自動(dòng)進(jìn)行一些數(shù)據(jù)葡秒、狀態(tài)的保存和恢復(fù)工作姻乓。
何時(shí)生命周期不回調(diào)onStop方法嵌溢?
當(dāng)原頁面未被完全覆蓋時(shí),即啟動(dòng)的頁面為Dialog或透明主題蹋岩,原頁面不會(huì)回調(diào)onStop方法赖草。
設(shè)置Dialog主題
Activity
<activity
android:name=".Main2Activity"
android:theme="@android:style/Theme.Dialog"/>
AppCompatActivity
<activity
android:name=".Main2Activity"
android:theme="@style/Theme.AppCompat.Dialog"/>
設(shè)置透明主題
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" />
實(shí)例驗(yàn)證
依據(jù)以上方法設(shè)置ActivityB主題,驗(yàn)證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: +++++++++++++++++++啟動(dòng)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誰先調(diào)用剪个?
前文說到新頁面調(diào)用onResume前秧骑,原頁面的onPause必須先調(diào)用,具體原因我們從源碼中獲取扣囊。下面貼一段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.
從上面這段源碼以及相應(yīng)注釋可以看出乎折,如果沒有設(shè)置RESUME_WHILE_PAUSING這個(gè)Flag,那么新頁面調(diào)用onResume時(shí)侵歇,原頁面的onPause必須先調(diào)用
骂澄。
系統(tǒng)配置發(fā)生改變時(shí)Activity被重新創(chuàng)建
Activity重建時(shí)的生命周期
當(dāng)系統(tǒng)的配置發(fā)生改變時(shí)(例如手機(jī)橫豎屏切換、系統(tǒng)語言切換等)盒至,Activity會(huì)被重新創(chuàng)建酗洒。此時(shí)Activity生命周期和創(chuàng)建時(shí)一樣,只不過這時(shí)候Activity會(huì)調(diào)用onSaveInstanceState
枷遂、onRestoreInstanceState
這一組方法來進(jìn)行頁面數(shù)據(jù)的緩存以及恢復(fù)(正常啟動(dòng)Activity時(shí)不會(huì)觸發(fā)該組方法)樱衷。
PS:Activity的數(shù)據(jù)緩存與恢復(fù)可以看本人另一篇文章
Android如何應(yīng)對(duì)內(nèi)存回收機(jī)制
如何避免配置修改后Activity被重建
如果不想系統(tǒng)配置修改后重啟Activity,也可以給configChanges添加不需要重啟的指定配置項(xiàng)酒唉。例如矩桂,橫豎屏、語言變化時(shí)不想重啟Activity痪伦,可這樣寫:
<activity
android:name=".Main2Activity"
android:configChanges="locale|orientation" />
PS:configChanges詳細(xì)配置請(qǐng)看本人另一篇文章
Android修改系統(tǒng)設(shè)置后Activity被重新創(chuàng)建
Activity被系統(tǒng)回收后再次重建
當(dāng)系統(tǒng)內(nèi)存不足時(shí)侄榴,Android系統(tǒng)會(huì)自動(dòng)回收一些低優(yōu)先級(jí)的進(jìn)程,或者回收一些已被停止的后臺(tái)Activity网沾。
Activity優(yōu)先級(jí)
Activity優(yōu)先級(jí)如下癞蚕,由高到低:
- 前臺(tái)Activity--正在和用戶交互的Activity。高優(yōu)先級(jí)辉哥。
- 可見但不可交互Activity--上層頁面為Dialog桦山、透明主題,即已Pause但未Stop的頁面醋旦。中優(yōu)先級(jí)恒水。
- 后臺(tái)Activity--已Stop的Activity。低優(yōu)先級(jí)饲齐。
Activity重建時(shí)的生命周期
Activity被重建時(shí)钉凌,Activity生命周期和新建時(shí)一樣,只不過這時(shí)候Activity也會(huì)調(diào)用onSaveInstanceState
捂人、onRestoreInstanceState
這一組方法來進(jìn)行頁面數(shù)據(jù)的緩存以及恢復(fù)(正常啟動(dòng)Activity時(shí)不會(huì)觸發(fā)該組方法)御雕。
PS:如何處理內(nèi)存被回收可以看本人另一篇文章
Android如何應(yīng)對(duì)內(nèi)存回收機(jī)制
NewIntent狀態(tài)下的生命周期
什么情況下會(huì)觸發(fā)onNewIntent回調(diào)方法矢沿?
這個(gè)問題我們從源碼中求解。下面貼一段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.
從注釋中可以看出饮笛,在不需要?jiǎng)?chuàng)建一個(gè)新的Activity實(shí)例時(shí)咨察,生命周期會(huì)回調(diào)onNewIntent方法。不需要?jiǎng)?chuàng)建新Activity實(shí)例主要有這兩種情況:
(1)啟動(dòng)模式為singleTask福青,且棧內(nèi)已存在待創(chuàng)建實(shí)例摄狱;
(2)啟動(dòng)模式為singleTop,且棧頂就是待創(chuàng)建實(shí)例无午。
觸發(fā)onNewIntent方法時(shí)媒役,Activity生命周期是怎樣的?
在singleTask和singleTop啟動(dòng)模式下宪迟,啟動(dòng)一個(gè)已存在的Activity(PS:只看在棧頂?shù)那闆r)酣衷,該Activity的生命周期會(huì)如何回調(diào)呢?
回調(diào)的時(shí)序應(yīng)該是onPause->onNewIntent->onResume次泽。
觸發(fā)onNewIntent回調(diào)的注意事項(xiàng)
在回調(diào)onNewIntent方法時(shí)穿仪,需要注意將onNewIntent傳入的intent替換為當(dāng)前Intent,否則新Intent附加值并不會(huì)被傳遞給頁面意荤。需要調(diào)用如下方法: