Android 開發藝術探索筆記之一 -- Android 的生命週期和啟動模式
學習內容:
- Activity 的生命週期和啟動模式以及 IntentFilter 的匹配規則分析
- 異常情況下的生命週期
- Activity 的啟動模式以及 Flags
- 隱式啟動下的 Intent 匹配
Activity 的生命週期全面分析
我的另一篇文章:詳解 Android&Fragment 的生命週期
此處只是記錄一下缺失的知識點,加以擴充。
建議本文與上文配合閱讀。
前置
生命週期分為兩類:
- 典型情況下的生命週期
- 另一部分是異常情況下的生命週期。
典型情況:指有使用者參與的情況下,Activity 所經過的生命週期的改變
異常情況:指 Activity 被系統回收或者由於當前裝置的 configuration 發生改變從而導致 Activity 被銷燬重建
典型情況下的生命週期
書中的兩個問題:
問題一:onStart 和 onResume、onPause 和 onStop 有什麼實質性的不同?
答:意義不同:onStart 和 onStop 是從Activity 是否可見這個角度來回撥;onResume 和 onPause 是從 Activity 是否處在前臺這個角度來回撥問題二:當前 Activity 為 A,此時開啟新的 Activity B,那麼 B 的 onResume 和 A 的 onPause 哪個先執行?
答:舊的Activity(A)執行完 onPause 之後,新的 Activity(B)的 onResume 才能執行。
這個問題在我原來寫的那篇文章中也提到過,只不過我得出這個結論是寫了個 Demo,測試得來的。而主席這裡,從原始碼分析得到結論,之後再通過例項測試驗證結論。可以說,我只是知道了這個結論就是這樣,但是卻不知道為什麼,原理是什麼。
異常情況下的生命週期
書中的兩種情況:
- 情況1:資源相關的系統配置發生改變導致 Activity 被殺死並重新建立。
- 系統配置發生改變後,Activity 會被銷燬,onPause、onStop、onDestroy 正常呼叫。
- Activity 是異常情況下終止,因而會呼叫 onSaveInstanceState 方法儲存狀態。
- 異常情況下終止,需要重建時,系統會預設為我們儲存當前 Activity 的檢視結構。
- 儲存和恢復 View 層級結構的工作流程(以儲存為例,恢復過程類似):委託思想
- 首先 Activity 意外終止時,呼叫 onSavedInstanceState 儲存資料
- 然後 Activity 委託 Window 儲存資料。
- 接著 WIndow 再委託它上面的頂級容器儲存資料(頂級容易是一個 ViewGroup 一般是 DecorView)
- 最後頂級容器一一通知它的子元素來儲存資料。
- 情況2:資源記憶體不足導致低優先順序的 Activity 被殺死
- 優先順序排序
- 前臺 > 可見但非前臺 -> 後臺
- 後臺任務保活:將後臺任務放入 Service 從而保證程式有一定的優先順序,這樣不會輕易被殺死。
- 優先順序排序
如何在系統配置發生改變後,避免 Activity 重建?
答:通過為 Activity 指定 configChanges 屬性,以此在特定情況下不讓系統重建 Activity,此時系統不會儲存恢復資料,而是呼叫了 onConfigurationChanged 方法,在此方法中我們可以做一些自己的特殊處理。
常用的屬性為 locale、orientation、keyboardHidden 這三個:locale 指裝置本地設定發生改變,一般是系統語言;orientation 指螢幕方向發生改變;keyboardHidden 指鍵盤的可訪問性發生了改變,比如用於調出了鍵盤。
Activity 的啟動模式
我的另一篇文章:深入理解 Android 的啟動模式
此處只是記錄一下缺失的知識點,加以擴充。
建議本文與上文配合閱讀。
Activity 的 LaunchMode
四種模式:
- standard:標準模式
- singleTop:棧頂複用模式
- singleTask:棧內複用模式
- singleInstance:單例項模式
singleTask 下的特殊情況:
假設目前有 2 個任務棧,前臺任務棧為 AB,後臺任務棧為 CD,且 CD 的啟動模式都是 singleTask:
- 如果此時啟動 D:整個後臺任務棧都被切換到前臺,即前臺此時為 ABCD。
- 如果此時啟動 C:那麼 D 會因為 singleTask 模式預設具備 clearTop 的效果而出棧,此時前臺任務棧為 ABC。
TaskAffinity 基礎
- TaskAffinity 標識 Activit有所需要的任務棧的名字。
- 該屬性主要與 singleTask 啟動模式或者 allowTaskReparenting 屬性配對使用。
TaskAffinity + singleTask
待啟動的 Activity 會執行在名字和 TaskAffinity 相同的任務棧中
TaskAffinity + allowTaskReparenting
當一個應用 A 啟動了應用 B 的某個 Activity 後,如果這個 Activity 的 allowTaskReparenting 屬性為 true 的話,那麼當應用 B 被啟動後,此 Activity 會直接從應用 A 的任務棧轉移到應用 B 的任務棧中。
Activity 的 Flags
見我的另一篇文章:深入理解 Android 的啟動模式
IntentFilter 的匹配規則
啟動 Activity 分為兩種:顯式呼叫和隱式呼叫。
- 顯式呼叫需要明確指定被啟動物件的元件資訊,包括包名和類名
- 隱式呼叫不需要明確指定元件資訊。
- 如果二者共存,以顯式呼叫為主。
隱式呼叫的匹配規則
隱式呼叫需要 Intent 能夠匹配目標元件的 IntentFilter 中所設定的過濾資訊,如果不匹配將無法啟動目標 Activity。
IntentFilter 中的過濾資訊有 action、category、data。
- 當三者都匹配時,IntentFilter 才匹配成功,才能啟動目標 Activity。
- 一個 Activity 可以有多個 intent-filter,一個 Intent 只要匹配任何一組 intent-filter 即可成功啟動對應的 Activity
1.action 的匹配規則
action 的匹配規則是 Intent 中的 action 必須能夠和過濾規則中的 action 匹配,這裡匹配指 action 的字串值完全一致。
一個過濾規則中可能有多個 action,只要 Intent 中的 action 能夠和過濾規則中的任何一個 action 相同都可匹配成功。反之,任何一個都不相同,則匹配失敗。
需要注意:action 區分大小寫。
2.category 的匹配規則
Intent 可以沒有 category,但是如果一旦有 category,那麼不管有幾個,每個都要能和過濾規則中的任何一個 category 相同。
startActivity 或者 startActivityForResult 方法啟動 Activity 時,預設會為 Intent 加上 android.intent.category.DEFAULT 這個 category。
3.data 的匹配規則
和 action 的匹配規則類似,Intent 必須含有 data 資料,並且 data 資料能夠完全匹配過濾規則中的某一個 data,這裡的完全匹配是指過濾規則中出現的 data 部分也出現在了 Intent 中的 data。
先介紹下data 的結構:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"
data 由兩部分組成:mimeType 和 URI。mime Type 指媒體型別,比如 image/jpeg、audio/mpeg4-generic 和 video/* 等,可以表示圖片、文字、視訊等不同的媒體格式;而 URI 包含的資料很多,URI 的結構如下:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
//例項
content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info
- Scheme:URI 的模式,如 http、file、content等,如果未指定,則 該URI無效。
- Host:URI 的主機名,比如 www.baidu.com,如果未指定,則 該URI無效
- Port:URI 的埠號,比如 80。
- Path、pathPattern 和 pathPrefix:三者表述路徑資訊,其中 path 表示完整路徑資訊;pathPattern 也表示完整的路徑資訊,但是可以包含萬用字元 "*";pathPrefix 表示路徑的字首資訊。
下面說一下 data 的指定:
- 指定完整的 data,必須呼叫 setDataAndType 方法
- setData 和 setType 互相沖突,會彼此消除對方的值。
避免隱式呼叫出錯
當隱式啟動一個 Activity 的時候,如果未加判斷,找不到匹配的 Activity,那麼會丟擲 android.content.ActivityNotFoundException 異常,解決方案:
- PackageManager 的 resolveActivity 方法或者 Intent 的 resolveActivity 方法:返回最佳匹配的 Activity 資訊,如果找不到匹配的 Activity 就會返回 null
- PackageManager 的 queryIntentActivities 方法:返回 所有成功匹配的 Activity 資訊。
補充說明:
- 不含 DEFAULT 這個 category 的 Activity 無法接收隱式 Intent
- 對於 Service,儘量使用顯式呼叫方式來啟動服務
- 通過以下設定表明入口 Activity,並且出現在系統的應用列表:
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
相關文章
- Android入門教程之Activity(生命週期,啟動...)Android
- Android Activity生命週期Android
- Android | Activity和Fragment最全生命週期+發現大牛AndroidFragment
- Activity生命週期與啟動模式模式
- Android之各生命週期Android
- Android開發藝術探索 第7章 動畫深入分析Android動畫
- iOS開發筆記(九):UIViewController的生命週期iOS筆記UIViewController
- Android學習筆記-Activity的啟動模式Android筆記模式
- Android View的生命週期詳解AndroidView
- Android Activity是如何啟動的?Activity的生命週期是如何呼叫的?Android
- Android Service生命週期淺析Android
- Flutter仿Android生命週期LifecycleStateFlutterAndroid
- Android四大元件之服務————服務的生命週期和啟動方式Android元件
- Android Activity生命週期的一點感悟Android
- Android:聊聊 MVP 中 Presenter 的生命週期AndroidMVP
- react生命週期筆記React筆記
- JSP筆記-生命週期JS筆記
- Android 監聽生命週期工具庫Android
- Android中元件生命週期完全解析Android元件
- Android全面解析之Activity生命週期Android
- 擼擼Android的羊毛(二)----Activity生命週期Android
- iOS-APP的啟動流程和生命週期iOSAPP
- Android-毛筆的探索與開發Android
- Android知識重溫之生命週期Android
- Android生命週期元件Lifecycle使用詳解Android元件
- 書海拾貝|開發藝術探索之 android 的訊息機制Android
- Android開發筆記Android筆記
- 2018.03.05 Android 記一次關於Fragment生命週期的討論。AndroidFragment
- Android啟動模式Android模式
- [譯] Android 生命週期備忘錄 —— 第四部分:ViewModel、半透明 Activity 及啟動模式AndroidView模式
- React生命週期學習筆記React筆記
- android基礎學習-android篇day17-Activity的生命週期(轉)Android
- [譯] android應用開發者,你們真的瞭解Activity的生命週期嗎?Android
- [譯] android應用開發者,你們真的瞭解Fragment的生命週期嗎?AndroidFragment
- 筆記 深入探索Android熱修復技術原理筆記Android
- Android四大元件——Activity——Activity的生命週期Android元件
- 瞭解Android核心元件活動生命週期————旋轉螢幕Android元件
- docker筆記23-pod的生命週期Docker筆記