Activity 生命周期
onCreate()
表示 activity 正在被創(chuàng)建韩脏,是所有聲明周期的第一個方法晌杰。在這個方法中,做一些初始化操作功炮,加載布局文件溅潜,初始化數(shù)據(jù)等。
onStart()
表示 Activity 正在被啟動薪伏,即將開始滚澜。這時 Activity 已經(jīng)可見了,但是還沒有出現(xiàn)在前臺嫁怀,還無法和用戶交互设捐〗枳牵可以理解為還沒給錢,能看不能摸(誤)萝招。
一般在 onCreate() 之后調(diào)用蚂斤,或者在 onRestart() 之后調(diào)用。
onResume()
表示給錢了即寒,現(xiàn)在 Activity 出現(xiàn)在了前臺并開始活動橡淆,也可以接受用戶事件。
onPause()
表示 Activity 正在停止母赵,可以做一些簡單的存儲數(shù)據(jù)逸爵、停止動畫之類的操作,但是不能耗時太長凹嘲,因為這個方法結(jié)束之后师倔,下一個 activity 才能執(zhí)行 onCreate()
onStop()
表示 Activity 即將停止,可以做一些稍微重量級的回收工作周蹭,也不能太耗時
onDestroy()
表示 Activity 即將被銷毀趋艘,最后一個生命周期回調(diào),釋放資源凶朗,回收內(nèi)存瓷胧,防止泄露
onRestart()
表示 Activity 正在重新啟動,一般指從不可見狀態(tài)回到可見狀態(tài)時會回調(diào)到這里棚愤。
比如回到桌面再看打開搓萧,或者跳轉(zhuǎn)到下一個 Activity 再回來。
Tips
- 一般來講宛畦,onStart() 和 onStop()瘸洛、onResume() 和 onPause() 是兩對回調(diào)方法,作用沒什么差別次和,只不過是兩個角度劃分反肋, onStart() 和 onStop() 是從 Activity 是否可見,onResume() 和 onPause() 是從 Activity 是否在前臺踏施;
- 起點 Activity 的 onPause() 執(zhí)行完畢后才能執(zhí)行終點 Activity 的 onCreate()石蔗,所以切記不能在onPause() 中做耗時操作;
異常情況下的生命周期回調(diào)
系統(tǒng)配置改變導致的 Activity 重建
最經(jīng)典的就是橫豎屏切換的場景畅形。用戶切換橫豎屏的時候抓督,Activity 會銷毀后重建,同時會調(diào)用 onSaveInstanceState() 方法來存儲數(shù)據(jù)束亏,然后在重建的時候會通過 onCreate() 的參數(shù)將之前的保存的 bundle 信息返回回來铃在,同時回調(diào) onRestoreInstanceState() 方法恢復數(shù)據(jù)。
如果是銷毀后重建,那 onCreate 方法的 Bundle 參數(shù)不為空定铜,會包含銷毀前保存的數(shù)據(jù)阳液;
onSaveInstanceState() 方法在 onStop() 之前調(diào)用,但相對于 onPause() 的調(diào)用時機并不固定;
onRestoreInstanceState() 方法在 onStart() 之后調(diào)用揣炕,相對于 onResume() 的調(diào)用時機不固定帘皿;
-
所有的 View 的狀態(tài)也都能得到保存和恢復,是通過 Activity 委托 Window畸陡,Window 委托 DecorView鹰溜,最后 DecorView 遍歷子元素,一一委托實現(xiàn)的丁恭。
所有的 View 都實現(xiàn)了 onSaveInstanceState() & onRestoreInstanceState() 方法來處理意外情況曹动。
在清單文件中設(shè)置 android:configChanges 屬性為 orientation 就可以禁止屏幕旋轉(zhuǎn)時重建。
資源內(nèi)存不足導致優(yōu)先級低的 Activity 被殺死
優(yōu)先級排序:可交互 > 可見 > 不可見牲览。
如果有任務(wù)脫離四大組件運行在后臺墓陈,那很快就會被系統(tǒng)殺死并回收資源。
比較好的處理方式是依托于 Service第献,運行于后臺贡必,保持一個比較高的優(yōu)先級。
Activity 啟動模式
啟動模式老生常談了庸毫,今天說點兒不一樣的仔拟。
先說設(shè)置啟動模式有兩種方式:
1、在清單文件中配置飒赃,standard利花,singleTask,singleTop盒揉,singleInstance晋被;
2兑徘、直接在啟動的時候通過給 Intent 設(shè)置標記位實現(xiàn)刚盈,優(yōu)先級更高,可以覆蓋掉清單文件的配置;
3挂脑、兩種方式其實不能簡單比較藕漱,因為在限定條件上有所不同,比如功能清單不能設(shè)置 clear_top 標志崭闲,而代碼無法設(shè)置 singleInstance 啟動模式肋联。
再說一下任務(wù)棧。
Activity 中有任務(wù)棧的概念刁俭,分為前臺任務(wù)棧和后臺任務(wù)棧橄仍,后臺任務(wù)棧中的 Activity 都處于暫停狀態(tài),用戶可以通過切換將后臺任務(wù)棧再次調(diào)到前臺。
默認情況下侮繁,一個程序的任務(wù)棧都是以包名為名的虑粥,但是開發(fā)者可以通過給 taskAffinity 屬性賦值來為某個 Activity 指定任務(wù)棧。指定任務(wù)棧一般要和 singleTask 或者 allowTaskReparenting 配合使用宪哩,否則沒什么意義娩贷。
這個后邊再展開說,先來看四個啟動模式锁孟。
standard
在標準啟動模式下彬祖,被啟動的 Activity 應(yīng)該運行在發(fā)起啟動的 Activity 所在的任務(wù)棧中。
舉例來說品抽,如果使用 getApplicationContext() 啟動 Activity储笑,系統(tǒng)就會直接報錯。因為 Application Context 非 Activity 類型桑包,沒有任務(wù)棧南蓬。
解決辦法是給待啟動的 Intent 添加一個 NEW_TASK 的標記,這時候就會為目標 Activity 新建一個任務(wù)棧啟動哑了,但是這時候本質(zhì)上就不是以標準模式啟動的了赘方,而是 singleTask;我們在前面說了弱左,代碼設(shè)置標記優(yōu)先級更高窄陡。
singleTop
棧頂復用,如果目標 Activity 位于棧頂就不再重新創(chuàng)建實例拆火,而是回調(diào) onNewIntent() 方法跳夭,從該方法的參數(shù)中能拿到這次請求的信息。
如果棧頂不是目標 Activity们镜,那就新建一個實例币叹,從頭完整走生命周期方法。
舉個栗子∧O粒現(xiàn)在任務(wù)棧里颈抚,ABCD 4 個 activity,A 底 D 頂嚼鹉。
1贩汉、如果再啟動一次 D,D 是 singleTop锚赤,那就還是 ABCD匹舞;
2、如果再啟動一次 C线脚,C 是 singleTop赐稽,那就是 ABCDC;
singleTask
棧內(nèi)復用叫榕,和 singleTop 差不多,位于棧頂?shù)脑捇卣{(diào) onNewIntent 方法姊舵;如果不位于棧頂翠霍,有幾種情況:
1、默認任務(wù)棧蠢莺,但是不在棧頂寒匙,比如說 ADBC,要以 singleTask 模式啟動 D躏将,singleTask 默認帶有 clearTop 的效果锄弱,任務(wù)棧里就會變成 AD
2、重新指定了任務(wù)棧祸憋,任務(wù)棧不存在会宪,實例也不存在,那就先創(chuàng)建任務(wù)棧蚯窥,然后創(chuàng)建 activity掸鹅,最后入棧;
singleInstance
加強版的 singleTask拦赠,singleTask 還可以位于默認任務(wù)棧里巍沙,這個是純單例,強制開啟一個新的任務(wù)棧荷鼠。自己一個人在一個任務(wù)棧里句携,還 clearTop,有一種獨孤求敗的感覺允乐。
說一個 taskAffinity 和 singleTask 配合的實例矮嫉。
A 正常啟動模式,B牍疏、C singleTask蠢笋,同時單獨設(shè)置 taskAffinity;
然后 A 啟動 B鳞陨,B 啟動 C昨寞,C 啟動 A,A 再啟動 B炊邦,這時候連續(xù)按下兩次返回鍵编矾,出現(xiàn)的是哪個 Activity熟史?
答案是桌面馁害。
首先,A 自己位于一個任務(wù)棧內(nèi)蹂匹,B碘菜、C 位于一個任務(wù)棧,且 singleTask,C 再去啟動標準模式的 A 時忍啸,A 會進入調(diào)用者的任務(wù)棧中仰坦,也就是 B、C 所在的棧计雌;
然后悄晃,A 再啟動一次 B,這時候棧結(jié)構(gòu)是 BCA凿滤,B 又是 singleTask妈橄,直接會將 CA 出棧,將 B 顯示會棧頂翁脆;
再然后眷蚓,這時候有兩個任務(wù)棧,一個是默認的反番,里邊有一個 A沙热;另一個是單獨開辟的,里邊有一個 B罢缸。
這時候連續(xù)按兩次返回篙贸,就退出應(yīng)用了,也就回到了桌面枫疆。
IntentFilter 匹配規(guī)則
IntentFilter 主要用于隱式調(diào)用歉秫。IntentFilter 主要有三種,action养铸、data雁芙、category。
<activity android:name="com.test.ThirdActivity">
<intent-filter>
<action android:name="com.test.action.a"/>
<action android:name="com.test.action.b"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.test.category.a"/>
<category android:name="com.test.category.b"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
action钞螟、data兔甘、category 可以有多個,只要有一個 Intent 能同時匹配鳞滨,就可以成功跳轉(zhuǎn)洞焙。
intent-filter 也可以分組聲明,Intent 匹配上任意一組 IntentFilter 也可以實現(xiàn)跳轉(zhuǎn)拯啦。
action
如果過濾規(guī)則中定義了 action澡匪,那 Intent 中就必須有 action,且能夠與某一個 action 完全相同才可以匹配成功褒链。
category
category 不是必須的唁情,如果在源碼中會自動加上 android.intent.category.DEFAULT
。
data
和 action 一樣甫匹,如果定義了就必須在 Intent 中攜帶甸鸟,否則匹配失敗惦费。
具體的 data 類型不再贅述,使用場景不多抢韭,簡單了解即可薪贫。
有一類 action 和 category 比較重要,它們就是:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
這二者共同作用的用來標明這是一個入口 activity刻恭,并且會出現(xiàn)在系統(tǒng)的應(yīng)用列表中瞧省,二者缺一不可。
另外鳍贾,針對 service 和 broadcast receiver臀突,PackageManager 同樣提供了類似的方法獲取成功匹配的組件信息。