Activity知識點詳解
一、什么是Activity
官方解釋:
The Activity class is a crucial component of an Android app, and the way activities are launched and put together is a fundamental part of the platform’s application model. Unlike programming paradigms in which apps are launched with amain()method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle.
Activity是Android應用的重要組成部分,它的啟動和組合方式是Android應用程序模型的一個基本部分。與使用 main ()方法啟動應用程序的編程范例不同,Android 系統通過調用與其生命周期的特定階段相對應的特定回調方法來啟動 Activity 實例中的代碼。
我們在日常的開發中接觸最多的可能就是Activity了,對於Activity我的理解是它作為Android四大組件之一,主要是給我們提供界面的展示和用戶交互。。這里要說下Android的四大組件,Activity、Service、Brocast、ContentProvider功能各不相同但是稱它們為四大組件主要是它們四個都是Android應用的入口。我們都知道Java是采用main ()方法啟動應用程序的,但是Android並沒有采用這種方式,Android設計了四個組件以這些組件為入口來啟動一個Android應用。
二、生命周期
生命周期作為Activity老生常談的知識點是我們必須要熟練掌握的。這里要分兩種情況去理解掌握:正常情況下的生命周期和異常情況下的生命周期。
正常情況下的生命周期
這可以說是Activity最基本的知識點了在此就不展開了,貼張圖
再次補充一個關於生命周期的問題就是處於哪些生命周期時是可以被殺死的。
onCreate、onStart()、onRestart()、onResume()當Activity處於這些生命周期時是不可被kill的。onPause()在Honeycomb(3.X版本)之前是可以被kill的,而從Honeycomb開始系統在Activity回調onStop()
之前是不會殺死Activity的,因為這樣可以確保在異常情況下onsaveinstancestate被調用,保存狀態。
(Android P開始onsaveinstancestate在onStop()之后被調用)
異常情況下的生命周期
我們主要注意以下兩種情況下的生命周期:
系統配置發生變化
比如常見的如屏幕方向發生變化,配置發生變化是會導致Activity銷毀重建的,如果我們想保持之前的Activity不被銷毀那么我們可以在manifest中設置對應的配置信息 ,之后當其變化時會觸發onConfigurationChanged回調此時是不會銷毀重建的。但是要注意的是觸發回調時當前組件(Activity)必須還在運行 如果組件被暫停 那么是不會觸發回調的 。
內存緊張導致Activity被殺死
因為Android總體資源有限當內存緊張時系統會根據一定的優先級殺死一些Activity。這里的優先級依次是:前台Activity>可見Activity>后台Activity>空進程。
除此之外我們還要了解onsaveinstancestate/onrestoreinstancestate回調。
onsaveinstancestate是Activity因為異常被系統kill時用來保存當前Activity的有關狀態和數據的,我們也可以在該回調中保存我們想要保存的數據以防止Activity因為異常被殺死而丟失數據。之后系統會在合適的時機重建該Activity此時就會觸發onrestoreinstancestate回調,在該回調里我們可以拿到之前保存的狀態和數據進行恢復(在oncreate中也可以拿到保存的數據不過需要進行判空,所以還是推薦在onrestoreinstancestate進行恢復)。
最后關於這兩個函數的回調時機,系統版本不同會有一些差異:
1、 api < 11,onSaveInstance在onPause之前執行
2、11 <= api < 28,onSaveInstance在onPause之后,onStop之前執行
3、api >= 28,onSaveInstance在onStop之后執行
三、啟動方式
分類一
顯示啟動
指明ComponentName有明確的啟動目標
隱式啟動
未指明ComponentName,通過匹配intentfilter找到可以啟動的目標
分類二
不帶返回值
通過startActivity
帶返回值
startActivityForResult啟動並在onActivityResult中接收返回的結果。
四、任務棧
Task是用戶在執行某項任務時與之交互的Activity的集合。按照每個Activity打開的順序排列在一個堆棧(先進后出)。一般來說處在棧頂的Activity是正在前台的Activity。
總結Activity和Task的默認行為:
- 當Activitya 啟動Activity b 時,Activity a 停止,但系統保持其狀態(如滾動位置和輸入到表單中的文本)。 如果用戶按下Back鍵回來那么a 恢復其狀態,b被彈出Task並被銷毀。
- 當用戶通過按下Home button當前Activity被停止並且它的任務進入后台。 系統保留任務中每個Activity的狀態。 如果用戶稍后通過選擇啟動該Task的啟動圖標恢復該任務,則該Task將到達前台並恢復堆棧頂部的Activity。
- Activity可以被多次實例化,同時可以從其他Task中實例化
一般而言我們不需要干預Task的默認行為,但是我們也可以通過以下方法去干預:
taskAffinity
Affinity表示Activity希望屬於哪個Task。 默認情況下,來自同一個應用程序的所有Activity彼此都有相同的Affinity。可以設置Taskaffinity 屬性來自定義Affinity。task自身的affinity決定於根Activity的affinity值也就是說同一個task中的所有Activity具有相同的affinity。
affinity在什么場合應用呢?
1.根據affinity重新為Activity選擇宿主task(與allowTaskReparenting屬性配合工作);
2.啟動一個Activity過程中Intent使用了FLAG_ACTIVITY_NEW_TASK標記,根據affinity查找或創建一個新的具有對應affinity的task
Affinity還有兩點要注意:
1、根activity的taskAffinity可以決定task的“名字”,activity在啟動時和re-parent時需要根據taskAffinity來確定該activity會出現在哪個task
2、優先級是activity中指定的taskAffinity>application中指定的taskAffinity>默認的包名
launchMode
Android提供了四種啟動模式:
- standard
默認模式 該模式下每次啟動activity都會創建新的activity實例。特殊情況,如果在Service或Application中啟動一個Activity,其並沒有所謂的任務棧,可以使用標記位Flag來解決。解決辦法:為待啟動的Activity指定FLAG_ACTIVITY_NEW_TASK標記位,創建一個新棧。 - singleTop
啟動一個activity如果該activity實例已經已在棧頂則復用並回調onnewintent。應用場景 推送跳轉activity - singleTask
啟動一個activity時會先找自己所屬的Task,如果該Task已經存在那么查看Task中是否有該activity實例 有則復用並回調onnewintent
如果所屬的Task還未創建那么就先創建Task然后再創建Activity實例並入棧 所以說singleTask 啟動模式的activity 是全局單例的。應用場景 app主頁 - singleInstance
可以看做是singleTask的加強版,改啟動模式下每次都會啟動一個新的Task並將activity實例放到Task 並且Task中只有這一個activity實例。應用場景 呼叫來電。
activity attributes或者intent flags
-
android:allowTaskReparenting
這個屬性用來標記一個Activity實例在當前應用退居后台后,是否能從啟動它的那個task移動到有共同affinity的task,“true”表示可以移動,“false”表示它必須呆在當前應用的task中,默認值為false 重新宿主的操作發生在應用退后台再次重啟過程中 -
android:alwaysRetainTaskState
如果用戶長時間離開Task,系統將清除除根Activity以外的所有Activity。 當用戶再次返回Task時,只恢復根Activity。但是設置該屬性為true后就不會發生清除,即使在很長一段時間之后,任務仍然保留其堆棧中的所有活動。 -
android:clearTaskOnLaunch
在Task的根Activity中,只要用戶離開Task並返回到該Task,堆棧就會被清除到根Activity。用戶總是返回到Task的初始狀態,即使離開Task只有一會兒。 -
android: finishOnTaskLaunch
它作用於一個單一的Activity,而不是一個完整的Task。 它會導致任何Activity消失,包括根Activity。用戶離開,然后返回到Task,則該Task不再存在。 -
FLAG_ACTIVITY_NEW_TASK
其效果與指定Activity為singleTask模式一致。系統會尋找或創建一個新的task來放置目標Activity,尋找時依據目標Activity的taskAffinity屬性進行匹配,如果找到一個task的taskAffinity與之相同,就將目標Activity壓入此task中,如果查找無果,則創建一個新的task,並將該task的taskAffinity設置為目標Activity的taskActivity,將目標Activity放置於此task -
FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致。 -
FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位於它上面的Activity都要出棧。如果和singleTask模式一起出現,若被啟動的Activity已經存在棧中,則清除其之上的Activity,並調用該Activity的onNewIntent方法。如果被啟動的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧,然后創建新的Activity實例並壓入棧中。如果和FLAG_ACTIVITY_NEW_TASK 一起使用時,則是一種在另一個Task中定位現有Activity並將其放置在能夠響應該意圖的位置的方法。 -
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果一個Intent中包含此屬性,則它轉向的那個Activity以及在那個Activity其上的所有Activity都會在task重置時被清除出task
最后說明下activity啟動時如何選擇task:
-
先判斷target activity能否在新task中啟動
singleTask/singleInstance的activity本身具有在新task中啟動的能力,standard/singleTop的activity要想擁有在新task中啟動的能力,需要在設置Intent.FLAG_ACTIVITY_NEW_TASK -
判斷target activity所在task
找一個taskAffinity的task去啟動,找不到就新建一個(這里會忽略了singleInstance獨占的task) -
根據TargetActivity的啟動模式判斷會如何啟動
五、相關問題
onWindowFocusChanged
在Activity窗口獲得或失去焦點時被調用,
1、創建時首次呈現在用戶面前;
2、當前Activity被其他Activity覆蓋;
3、當前Activity轉到其他Activity或按Home鍵回到主屏,自身退居后台;
4、用戶退出當前Activity。
以上幾種情況都會調用onWindowFocusChanged,並且當Activity被創建時是在onResume之后被調用,當Activity被覆蓋或者退居后台或者當前Activity退出時,它是在onPause之后被調用
這個方法在某種場合下還是很有用的,例如程序啟動時想要獲取視特定視圖組件的尺寸大小,在onCreate中可能無法取到,因為窗口Window對象還沒創建完成,這個時候我們就需要在onWindowFocusChanged里獲取
其他應用問題:
- activity間傳遞數據
- 知曉當前activity
- 關閉所有activity
- 雙擊退出app
- 保存activity狀態
面試常見知識點
Activity A跳轉到Activity B 兩者經歷怎樣的生命周期
未配置configchanges情況下屏幕發生旋轉時 當前Activity的生命周期是怎樣變化的