本文不適合入門新手蝎土,適合進(jìn)階者閱讀视哑。
0. 提問(wèn)
- onStart和onResume有什么區(qū)別?onPause和onStop有什么區(qū)別誊涯?打開一個(gè)新Activity時(shí)的回調(diào)順序挡毅?
- 4種啟動(dòng)模式的含義?
- 任務(wù)棧的作用暴构?Activity一定會(huì)放入其taskAffinity屬性所聲明的棧中嗎跪呈?
一. 生命周期
1. 順序
2. 詳細(xì)作用
- onCreate:生命周期內(nèi)只調(diào)用1次,用于初始化界面取逾、必要對(duì)象創(chuàng)建庆械、基礎(chǔ)邏輯、恢復(fù)數(shù)據(jù)菌赖、注冊(cè)廣播等
- onStart:界面由完全不可見(不包括被透明界面遮擋)變?yōu)榭梢姇r(shí)調(diào)用,利用這個(gè)特性處理一些業(yè)務(wù)邏輯
- onResume:界面可點(diǎn)擊交互沐序,不被頂層其他任何Activity遮擋琉用;開始執(zhí)行界面交互操作
- onPause:界面不可點(diǎn)擊交互,被其他Activity遮擋策幼,部分可見邑时;此時(shí)應(yīng)當(dāng)停止交互相關(guān)等耗資源的操作,如動(dòng)畫特姐、相機(jī)等
- onStop:界面完全不可見晶丘;保存重要數(shù)據(jù),而不在onDestroy中執(zhí)行唐含,因?yàn)锳ctivity在后臺(tái)時(shí)進(jìn)程被殺浅浮,則不調(diào)用
- onDestroy:生命周期內(nèi)只調(diào)用1次,界面完全銷毀捷枯,用于執(zhí)行資源釋放滚秩、反注冊(cè)廣播等
- onRestart:界面由stopped狀態(tài)下被再次打開時(shí)調(diào)用
Tips:注冊(cè)、反注冊(cè)應(yīng)當(dāng)在成對(duì)的生命周期回調(diào)方法里執(zhí)行
3. onStart和onResume?
onStart和onResume都是可見淮捆,區(qū)分在于onResume可點(diǎn)擊交互郁油,用戶可以操作界面本股。
4. onPause和onStop?
- 當(dāng)從Activity A打開一個(gè)透明屬性的Activity B時(shí),A只會(huì)調(diào)用onPause方法桐腌,而onStop不會(huì)調(diào)用拄显。此時(shí),A處于部分可見狀態(tài)案站,但不可交互躬审。同理,此時(shí)按返回鍵關(guān)閉B返回A嚼吞,只會(huì)調(diào)用A的onResume方法盒件。
- 從A打開B,若B不帶透明屬性:方法調(diào)用順序如下:A.onPause → B.onCreate → B.onStart(B開始可見)→ B.onResume → A.onStop舱禽。所以兩個(gè)方法還是有所區(qū)分側(cè)重的炒刁,兩個(gè)方法都不當(dāng)做耗時(shí)操作,特別是onPause方法誊稚,會(huì)影響界面B的打開翔始,所以稍微重點(diǎn)的計(jì)算操作方到onStop中,耗時(shí)的當(dāng)然是異步處理里伯。
5. 異常狀態(tài)下的生命周期
1. 系統(tǒng)配置改變
如屏幕旋轉(zhuǎn)城瞎、鍵盤、語(yǔ)言等等疾瓮,會(huì)觸發(fā)Activity重新創(chuàng)建脖镀。若想要這些改變時(shí),不觸發(fā)Activity重啟狼电,可以通過(guò)在AndroidManifest里設(shè)置activity的configChanges屬性蜒灰。常用的有l(wèi)ocale(語(yǔ)言區(qū)域)、orientation(屏幕方向)肩碟、keyboardHidden(鍵盤無(wú)障礙功能)强窖、screenSize(當(dāng)前可用屏幕尺寸發(fā)生了變化,旋轉(zhuǎn)屏幕尺寸會(huì)觸發(fā))削祈。具體參照官網(wǎng)API指南翅溺。
2. 系統(tǒng)資源不足
Activity優(yōu)先級(jí)從高到低,分3種:
Ⅰ. 前臺(tái):可交互
Ⅱ. 可見非前臺(tái):比如打開了一個(gè)對(duì)話框或者透明Activity
Ⅲ. 后臺(tái):跳轉(zhuǎn)其他Activity
內(nèi)存不足時(shí)髓抑,從低到高進(jìn)行銷毀咙崎。
二. 狀態(tài)保存與恢復(fù)
當(dāng)Activity跳轉(zhuǎn)到其他Activity,或者按Home鍵后吨拍,在后臺(tái)由于資源不足被系統(tǒng)回收叙凡,再次打開時(shí)若想恢復(fù)原有的數(shù)據(jù),則需要通過(guò)Bundle進(jìn)行數(shù)據(jù)存儲(chǔ)與恢復(fù)密末。
- 保存狀態(tài):在onStop方法之前握爷,系統(tǒng)會(huì)調(diào)用onSaveInstanceState方法跛璧,在此處存儲(chǔ)狀態(tài)。
- 恢復(fù)狀態(tài):在onCreate方法里進(jìn)行恢復(fù)新啼,要先對(duì)參數(shù)savedInstanceState進(jìn)行判空追城。也可以在onRestoreInstanceState方法里進(jìn)行恢復(fù),該方法在onStart之后調(diào)用燥撞,并且只有數(shù)據(jù)需要恢復(fù)時(shí)系統(tǒng)才會(huì)調(diào)用座柱,所以此處savedInstanceState無(wú)需判空。
三. LaunchMode-啟動(dòng)模式
1. 設(shè)置方法
- AndroidMenifest配置:
無(wú)法設(shè)置FLAG_ACTIVITY_CLEAR_TOP標(biāo)識(shí) - 代碼中設(shè)置intent.addFlags():若與第一種同時(shí)存在物舒,則以本方式為準(zhǔn)色洞。
無(wú)法設(shè)置singleInstance模式
2. Activity任務(wù)棧
- 用于組合存放Activity
- 采用“后進(jìn)先出”的棧結(jié)構(gòu)
-
棧的拼接:從棧A啟動(dòng)棧B后,按返回鍵冠胯,則先將棧B回退到空之后火诸,再進(jìn)入棧A≤欤可見圖示 棧的拼接
棧拼接后置蜀,不代表兩個(gè)棧都合并了,只是返回棧拼接而已悉盆。如上圖盯荤,處于第二步時(shí),若按Home鍵返回桌面焕盟,再按多任務(wù)鍵打開綠色的任務(wù)棧秋秤,這時(shí)候兩個(gè)任務(wù)棧不再拼接,按返回鍵后脚翘,退出綠色的棧后返回桌面灼卢。同理,若多任務(wù)鍵切換到藍(lán)色的棧堰怨,棧的頂部也不會(huì)有綠色的棧的內(nèi)容。
Home鍵回桌面打開應(yīng)用蛇摸、多任務(wù)鍵切換任務(wù)棧备图,都是直接打開目標(biāo)任務(wù)棧,之前的棧的拼接都會(huì)失效赶袄。
- 查看信息命令: adb shell dumpsys activity
3. LaunchMode的4種類型
standard:標(biāo)準(zhǔn)模式:每次啟動(dòng)一個(gè)Activity都會(huì)創(chuàng)建一個(gè)新的實(shí)例揽涮,并加入到當(dāng)前任務(wù)棧的頂部
singleTop:棧頂復(fù)用模式:若打開的Activity位于即將放入的棧的頂部,則復(fù)用饿肺,不會(huì)創(chuàng)建新的實(shí)例蒋困。按照onPause → onNewIntent → onResume的順序觸發(fā),可以onNewIntent內(nèi)處理業(yè)務(wù)敬辣。
singleTask:棧內(nèi)復(fù)用模式:Activity A在棧S1雪标,若A打開B(singleTask)
- B目標(biāo)棧為S2零院,S2不存在:則創(chuàng)建S2,并將B加入到棧中村刨。standard和singleTop不具備該特性告抄。
- B目標(biāo)棧為S1(或S2),S1(或S2)存在嵌牺,棧內(nèi)無(wú)B:創(chuàng)建B放入棧頂打洼。
- B目標(biāo)棧為S1(或S2),S1(或S2)存在逆粹,棧內(nèi)有B:復(fù)用B募疮,清空B之上的Activity,回調(diào)onNewIntent方法僻弹。
- singleInstance:?jiǎn)螌?shí)例模式:單獨(dú)位于一個(gè)任務(wù)棧中阿浓,棧中不會(huì)有其他Activity,單例奢方,你懂的搔扁,還是onNewIntent。
4. 標(biāo)識(shí)Flags
- FLAG_ACTIVITY_NEW_TASK:效果不等同于"singleTask"s帧8宥住!(《Android開發(fā)藝術(shù)探索》此書對(duì)于這點(diǎn)有誤)
驗(yàn)證方式:Manifest中配置為singleTask的Activity鹊奖,通過(guò)一個(gè)application的context來(lái)啟動(dòng)一個(gè)聲明為singleTask的Activity來(lái)進(jìn)行測(cè)試苛聘,會(huì)報(bào)錯(cuò)。因?yàn)樵诮馕瞿繕?biāo)Activity屬性之前忠聚,系統(tǒng)對(duì)context進(jìn)行檢測(cè)设哗,導(dǎo)致報(bào)錯(cuò),位于源碼中的ContextImpl.startActivity方法中两蟀。
正確理解如下(通過(guò)源碼理解測(cè)試):
打開的Activity的目標(biāo)棧如果不存在网梢,則創(chuàng)建棧,并且把Activity放到棧中赂毯。
-
打開的Activity的目標(biāo)棧如果存在战虏,則再分兩種情況:
- Activity未打開過(guò):創(chuàng)建Activity放入棧頂;
- Activity已經(jīng)打開過(guò)(無(wú)論是否被銷毀):
- 若Activity不在棧頂党涕,只會(huì)將該棧移動(dòng)到前臺(tái)烦感,不會(huì)創(chuàng)建新的Activity。(比如A膛堤、B同個(gè)目標(biāo)棧手趣,先打開A,A打開B肥荔,此時(shí)若B打開A绿渣,則是沒有反應(yīng)的朝群,不會(huì)跳轉(zhuǎn)到A);
- 若Activity在棧頂怯晕,且是使用Standard模式潜圃,則會(huì)創(chuàng)建新的Activity實(shí)例加到棧頂。
FLAG_ACTIVITY_SINGLE_TOP:效果如"singleTop"
FLAG_ACTIVITY_CLEAR_TOP:singleTask自帶該效果舟茶。
特別組合:被啟動(dòng)的Activity使用standard模式谭期,則會(huì)將它以及它以上的Activity都出棧,創(chuàng)建新的Activity放入棧中吧凉。
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:不出現(xiàn)在多任務(wù)列表中隧出。
5. 應(yīng)該進(jìn)入哪個(gè)任務(wù)棧?(難點(diǎn))
- taskAffinity:官方翻譯為親和關(guān)系阀捅,而非棧名胀瞪,表示更傾向于進(jìn)入哪個(gè)棧。所以不是設(shè)置了該屬性的Activity饲鄙,就是在屬于這個(gè)名的棧中凄诞。
- taskAffinity不設(shè)置時(shí),則默認(rèn)為包名忍级;設(shè)置為空帆谍,則為當(dāng)前Activity的包名路徑
- 當(dāng)A啟動(dòng)一個(gè)聲明為standard、singleTop的B時(shí)轴咱,且不帶FLAG_ACTIVITY_NEW_TASK汛蝙,則只會(huì)加入到A所在的棧頂,不會(huì)加入B所配置taskAffinity所聲明的棧頂朴肺。
- 不嚴(yán)謹(jǐn)?shù)母爬ǎ褐挥衧ingleTask窖剑、singleInstance或者帶FLAG_ACTIVITY_NEW_TASK等帶創(chuàng)建棧能力的方式啟動(dòng),才會(huì)讓taskAffinity生效戈稿。
- allowTaskReparenting這個(gè)屬性西土,也會(huì)讓taskAffinity生效。比如棧S1中的A啟動(dòng)設(shè)置了taskAffinity的B鞍盗,無(wú)論B使用什么啟動(dòng)模式需了,B都會(huì)被放入其taskAffinity所聲明的棧。
四. 文章引用
本文是在學(xué)習(xí)了以下文章后橡疼,進(jìn)行案例測(cè)試后的總結(jié)歸納援所,強(qiáng)烈推薦閱讀以下書籍庐舟、博客欣除。LaunchMode這部分知識(shí)特別需要代碼測(cè)驗(yàn),才能理清幾個(gè)關(guān)鍵細(xì)節(jié)挪略。