關(guān)鍵詞:Activity / 生命周期 / 啟動(dòng)模式 / IntentFilter
Activity 是界面,除了 Window / Dialog / Toast 我們見到的就只有 Activity 了。 本次梳理主要包括:Activity 生命周期、啟動(dòng)模式、IntentFilter 匹配規(guī)則。
| 一. 典型情況下的生命周期: | 被用戶參與的生命周期的改變 |
| 二. 異常情況下的生命周期: | 被系統(tǒng)回收或由于當(dāng)前設(shè)備的 Configuration 發(fā)生改變,導(dǎo)致 Activity 被銷毀重建 |
【一. 典型情況下的生命周期】
| onCreate: | 做一些初始化的工作(setContentView 加載界面布局資源、初始化 Activity 所需的數(shù)據(jù)) |
| onStart: | 正在啟動(dòng),Activity 已經(jīng)可見但是沒有出現(xiàn)在前臺(tái),無法與用戶交互,還處于后臺(tái) |
| onResume: | Activity 已經(jīng)可見而且開始活動(dòng),可以與用戶交互,已處于前臺(tái) |
| onPause: | 正在停止,緊接著調(diào)用 onStop |
| onStop: | 就要即將停止,做不太耗時(shí)的重量級(jí)的回收工作 |
| onRestart: | 由不可見到重新可見,用戶行為導(dǎo)致 onPause → onStop → 回到該 Activity |
| onDestroy: | 即將被銷毀,生命周期的最后一個(gè)回調(diào),回收和最終資源的釋放 |

對(duì)此需要知道的幾種情況 ↓ 1. 用戶按下 back 鍵返回時(shí),回調(diào) onPause → onStop → onDestroy 2. 用戶打開新的 Activity 或切換到桌面,回調(diào) onPause → onStop ,如果新 Activity 采用的是透明主題,就不會(huì)回調(diào) onStop 了 3. 第一次啟動(dòng),回調(diào) onCreate → onStart → onResume ; 再次回到 Activity,回調(diào) onRestart → onStart → onResume 4. 就整個(gè)生命周期而言,onCreate 和 onDestroy 只會(huì)被回調(diào)一次 5. onStart 和 onStop 是從 Activity 是否可見的角度來設(shè)計(jì)回調(diào)的,onResume 和 onPause 是從 Activity 是否位于前臺(tái)的角度來回調(diào)的 6. 當(dāng)前為 Activity A ,這時(shí)用戶打開了 Activity B,過程是:A 先 onPause,然后 B onResume(對(duì)于 Android 運(yùn)行的機(jī)制在不同的 Android 版本上具有延續(xù)性,各個(gè)版本應(yīng)該都是這個(gè)順序) 7. 不同在 onPause 中做重量級(jí)的操作,因?yàn)楸仨殘?zhí)行完 onPause ,新的 Activity 才能 onResume,應(yīng)該盡量在 onStop 中做操作,從而使新的 Activity 能夠盡快的顯示出來并切換到前臺(tái)
【二. 異常情況下的生命周期】
| 有兩種情況: |
|---|
| 資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致 Activity 被殺死并重新創(chuàng)建 |
| 資源不足導(dǎo)致優(yōu)先級(jí)較低的 Activity 被殺死 |
關(guān)于第 1 種情況需要知道的幾點(diǎn) ↓
當(dāng)應(yīng)用程序啟動(dòng)時(shí),系統(tǒng)會(huì)根據(jù)當(dāng)前的設(shè)備情況去加載合適的 Resources 資源如果系統(tǒng)配置發(fā)生了改變,比如,豎屏切換至橫屏,而我們的 Activity 沒有做特殊的處理,就會(huì)被銷毀并重新創(chuàng)建,參考圖2看圖2就知道,在異常情況下終止的 Activity,系統(tǒng)會(huì)調(diào)用 onSaveInstanceState 來保存當(dāng)前的 Activity 狀態(tài),onSaveInstanceState 方法的調(diào)用時(shí)機(jī)是在 onStop 之前(該方法只會(huì)出現(xiàn)在 Activity 被異常終止的情況下,正常情況下不會(huì)回調(diào)該方法)而當(dāng) Activity 被重新創(chuàng)建的時(shí)候,系統(tǒng)會(huì)調(diào)用 onRestoreInstanceState 方法,Activity 銷毀時(shí) onSaveInstanceState 方法所保存的 Bundle 對(duì)象作為參數(shù)傳給 onRestoreInstanceState 和 onCreate 方法有個(gè)區(qū)別: onRestoreInstanceState 一旦被調(diào)用,其參數(shù) Bundle saveInstanceState 是一定有值的,而 onCreate 是正常啟動(dòng)的話,其參數(shù) Bundle saveInstanceState 為 null,要額外判斷是否為空通過 onRestoreInstanceState 和 onCreate 方法可以判斷 Activity 是否被重建了,如果是的,就取出之前保存的數(shù)據(jù)并且進(jìn)行恢復(fù)onRestoreInstanceState 的調(diào)用時(shí)機(jī)發(fā)生在 onStart 之后(從時(shí)序上說)在 onSaveInstanceState 和 onRestoreInstanceState 方法中系統(tǒng)自動(dòng)為我們做了一些恢復(fù)工作,比如文本框用戶輸入的數(shù)據(jù)、ListView 滾動(dòng)的位置這些 View 相關(guān)的狀態(tài)
PS:關(guān)于保存和恢復(fù) View 層次結(jié)構(gòu) 系統(tǒng)的工作流程是一種典型的委托思想,上層委托下層,父容器委托子元素去處理一件事情(View 的繪制,事件的分發(fā)也都是采用類似的思想)。 過程大概是:
Activtiy 被意外終止,會(huì)調(diào)用 onSaveInstanceState 去保存數(shù)據(jù)Activity 會(huì)委托 Window 去保存數(shù)據(jù)Window 再委托它上面的頂級(jí)容器去保存數(shù)據(jù)(頂級(jí)容器是一個(gè) ViewGroup,一般說很可能是 DecorView)頂級(jí)容器再去一一通知它的子元素來保存數(shù)據(jù),至此整個(gè)數(shù)據(jù)保存過程就完成了關(guān)于第 2 種情況需要知道的幾點(diǎn) ↓
數(shù)據(jù)存儲(chǔ)與恢復(fù)過程與情況一完全一致Activity 的優(yōu)先級(jí):前臺(tái) Activity > 可見但非前臺(tái) Actiivty > 后臺(tái) Activity前臺(tái) Activity 正在和用戶交互,優(yōu)先級(jí)最高可見但非前臺(tái) Activity 比如彈有對(duì)話框的 Activity后臺(tái) Activity 被暫停的 Activity 比如執(zhí)行了 onStop 優(yōu)先級(jí)最低一般將后臺(tái)工作放在 Service 中以保證具有一定的優(yōu)先級(jí),就不會(huì)輕易被系統(tǒng)殺死,如果一個(gè)進(jìn)程中沒有四大組件在執(zhí)行,很快便會(huì)被系統(tǒng)殺死PS:讓 Activity 在屏幕旋轉(zhuǎn)的時(shí)候不重新創(chuàng)建:
android:configuration="orientation|screenSize"【目前有四種啟動(dòng)模式】
| 模式 | 中文名 |
|---|---|
| standard: | 標(biāo)準(zhǔn)模式 |
| singleTop: | 棧頂復(fù)用模式 |
| singleTask: | 站內(nèi)復(fù)用模式 |
| singleInstance: | 單實(shí)例模式 |
在默認(rèn)情況下,多次啟動(dòng)同一個(gè) Activity 的時(shí)候,系統(tǒng)會(huì)創(chuàng)建多個(gè)實(shí)例并把它們一一放入任務(wù)棧中,單擊 back 鍵的時(shí)候,這些 Activity 會(huì)回退。任務(wù)棧“后進(jìn)先出”的棧結(jié)構(gòu),棧中沒有 Activity 的時(shí)候系統(tǒng)會(huì)回收這個(gè)任務(wù)棧。
standard 模式: 系統(tǒng)默認(rèn)模式。誰(shuí)啟動(dòng)了這個(gè) Activity, 這個(gè) Activity 就進(jìn)入誰(shuí)的任務(wù)棧中。比如,A 啟動(dòng)了 B(B是標(biāo)準(zhǔn)模式),則 B 會(huì)進(jìn)入 A 所在的任務(wù)棧中。singleTop 模式: 新 Activity 已經(jīng)位于棧頂,則不會(huì)被重新創(chuàng)建,onNewIntent 方法被回調(diào);若實(shí)例已存在但不位于棧頂,那么新的 Activity 仍然會(huì)重新重建。singleTask 模式: 單實(shí)例模式。對(duì)于 Activity A 是 singleTask 模式,系統(tǒng)會(huì)首先尋找是否存在 A 想要的任務(wù)棧,如果不存在,就創(chuàng)建一個(gè)任務(wù)棧,然后創(chuàng)建 A 的實(shí)例之后把 A 放在棧中。如果存在 A 需要的任務(wù)棧,就再看是否存在 A 的實(shí)例在棧中,如果有實(shí)例存在就把 A 調(diào)到棧頂并調(diào)用它的 onNewIntent 方法(站內(nèi)復(fù)用原則),如果實(shí)例不存在就創(chuàng)建 A 的實(shí)例并把 A 壓入棧中。singleInstance 模式: 單實(shí)例模式。singleTask 的加強(qiáng)版。加強(qiáng)的一點(diǎn):這種 Activity 只能單獨(dú)的位于一個(gè)任務(wù)棧中(創(chuàng)建新的任務(wù)棧)。舉有個(gè)小板栗:目前站內(nèi)的情況是 ABCD,A 是棧底,D 在棧頂。如果 D 的啟動(dòng)模式為 singleTop 那么站內(nèi)的情況仍然是 ABCD;如果 D 的啟動(dòng)模式為 standard,那么由于 D 被重新創(chuàng)建。導(dǎo)致站內(nèi)的情況變?yōu)?ABCDD;
PS:什么是所謂的 Activity 需要的任務(wù)棧? - 任務(wù)棧有一個(gè)參數(shù):TaskAffinity,任務(wù)相關(guān)性。TaskAffinity 標(biāo)識(shí)了一個(gè) Activity 所需要的任務(wù)棧的名字。默認(rèn)為應(yīng)用的包名。也可單獨(dú)指定自定義 TaskAffinity 屬性。TaskAffinity 主要和 singleTask 或者 allowTaskPeparenting 屬性配對(duì)使用,否則沒有意義; - 任務(wù)棧分為 前臺(tái)任務(wù)棧 和 后臺(tái)任務(wù)棧(Activity 位于暫停狀態(tài),用戶通過切換將后臺(tái)任務(wù)棧再次調(diào)用到前臺(tái));
【給 Activity 指定啟動(dòng)模式的兩種方式】
方式一:AndroidManifest.xml
<activity android:name="io.github.isayes.MainActivity" android:configuration="screenLayout" android:launchMode="singleTask" android:label="@string/app_name" />方式二:在 Intent 中設(shè)置標(biāo)志位
Intent intent = new Intent();intent.setClass(MainActivity.this, SecondActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 實(shí)際上就是 singleTask 模式startActivity(intent);對(duì)此需要知道的以下幾點(diǎn) ↓
第二種方式的優(yōu)先級(jí)要高于第一種,如果兩種同時(shí)使用,則方式二覆蓋方式一第一種方式直接為 Activity 設(shè)定 FLAG_ACTIVITY_CLEAR_TOP 標(biāo)識(shí)第二種方式無法為 Activity 指定 singleInstance 模式singleTask 模式的 Activity 切換到棧頂會(huì)導(dǎo)致它上面的棧內(nèi)的 Activity 出棧【 Activity 的 Flags】
大部分情況下,我們不需要為 Activity 指定標(biāo)記位
FLAG_ACTIVITY_NEW_TASK = XML singleTaskFLAG_ACTIVITY_SINGLE_TOP = XML singleTopFLAG_ACTIVITY_CLEAR_TOP 一般和 singleTask 模式一起出現(xiàn),當(dāng)它啟動(dòng)時(shí),在同一個(gè)任務(wù)棧中所有位于它上面的 Activity 都要出棧FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = XMLandroid:excludeFromRecents="true"| 啟動(dòng) Activity 分為兩種: |
|---|
| 顯示調(diào)用 |
| 隱式調(diào)用 |
顯示調(diào)用需要明確地指定被啟動(dòng)對(duì)象的組件信息,包括包名類名; 隱式調(diào)用不需要明確指定組件信息;
隱式調(diào)用需要 Intent 能夠匹配目標(biāo)組件的 IntentFilter 中設(shè)置的過濾信息,如果不匹配將無法啟動(dòng)目標(biāo) Activity。IntentFilter 中過濾的信息有 action / category / data
關(guān)于 action 所要知道的幾點(diǎn) ↓
我們可以自定義匹配規(guī)則:Intent 中的 action 必須能夠和過濾規(guī)則中的 action 匹配(action 字符串完全一樣)區(qū)分大小寫關(guān)于 category 所要知道的幾點(diǎn) ↓
是一個(gè)字符串系統(tǒng)中預(yù)定義了,但是我們也可以自定義action 要求 Intent 中必須有一個(gè) action 與過濾規(guī)則中的某個(gè) action 相同,而 category 要求 Intent 中可以沒有 category,而一旦有就需要有匹配關(guān)于 data 所需要知道的幾點(diǎn) ↓
如果過濾規(guī)則中定義了 data ,則 Intent 中必須也要定義可匹配的 data。data 的語(yǔ)法:兩部分組成,URI + mimeType
<data android:scheme="string" android:host="string" android:port="string" android:path="string" android:pathPattern="string" android:path<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]End.
Note by HF. Learn from 《Android 開發(fā)藝術(shù)探索》
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注