生命周期
四大啟動模式
標(biāo)識位
Task棧
Android
1.初識 Activity
- 四大組件之一
- 與用戶交互的接口,提供了一個用戶完成相關(guān)操作的窗口
- 通過生命周期的方法來管理自身的創(chuàng)建與銷毀
- activity 是 Context 的子類
2.Android 任務(wù)棧( Task )
- 棧結(jié)構(gòu),后進(jìn)先出,用于存放 Acitivity 組件
淺顯理解:
- 打開一個新的Activity ---> 在任務(wù)棧的結(jié)構(gòu)中添加一個Activity組件
- 退出當(dāng)前Activity ---> 任務(wù)棧的結(jié)構(gòu)中減少一個Activity組件
- 一個任務(wù)棧包含了一個activity的集合
android系統(tǒng)可以通過Task有序地管理每個activity,并決定哪個Activity與用戶進(jìn)行交互:
只有在任務(wù)棧棧頂的activity才可以跟用戶進(jìn)行交互(這里的交互就是指點擊、輸入文字等操作)
- Task和activity默認(rèn)啟動方式
啟動一個Application的時候,系統(tǒng)會為它默認(rèn)創(chuàng)建一個對應(yīng)的Task,用來放置根Activity(應(yīng)用程序啟動的第一個Activity)。默認(rèn)啟動Activity會放在同一個Task中,新啟動的Activity會被壓入啟動它的那個Activity的棧中,并且顯示它。當(dāng)用戶按下回退鍵時,這個Activity就會被彈出棧,按下Home鍵回到桌面,再啟動另一個應(yīng)用,這時候之前那個Task就被移到后臺,成為后臺任務(wù)棧,而剛啟動的那個Task就被調(diào)到前臺,成為前臺任務(wù)棧,Android系統(tǒng)顯示的就是前臺任務(wù)棧中的Top實例Activity。
ps
:activity還有其他啟動方式,在文章末尾介紹
- task是可以跨應(yīng)用的
有的Activity,雖然不在同一個app中,但為了保持用戶操作的連貫性,把他們放在同一個任務(wù)(Task)中。
例如,在我們的應(yīng)用中的一個Activity A中點擊發(fā)送郵件,會啟動郵件程序的一個Activity B來發(fā)送郵件,這兩個activity是存在于不同app中的,但是被系統(tǒng)放在一個任務(wù)(Task)中,這樣當(dāng)發(fā)送完郵件后,用戶按back鍵返回,可以返回到原來的Activity A中,這樣就確保了用戶體驗。
- 退出應(yīng)用時必須清空棧內(nèi)所有Activity,才能銷毀Task
3. Activity的四種形態(tài)
狀態(tài)名 | 解釋 | 狀態(tài) |
---|---|---|
Active/Running | 運行狀態(tài):位于棧頂,正好處于屏幕最前方 | 可見+可交互 |
Paused | 暫停狀態(tài):失去了焦點,不能與用戶交互,但仍然可見(比如棧頂?shù)?Activity是透明或沒有鋪滿屏幕) | 可見+不可交互 |
Stopped | 停止狀態(tài):對用戶不可見,也不能交互 | 不可見+不可交互 |
Killed | 銷毀狀態(tài):由于人為或者系統(tǒng)原因被銷毀 | 不可見+不可交互 |
在每個狀態(tài),Android 系統(tǒng)對 Activity 都寫了相應(yīng)的回調(diào)方法。因此,我們在程序中寫 Android時,一般都是繼承 Activity 時,一般都是繼承 Acitivity 類并重寫相應(yīng)的回調(diào)方法
4. Activity的生命周期
4.1 Activity的正常一生
oncreate()->onstart()->onResume()->onRestart()->onPouse()->onStop()->onDestory()
onCreat()
: 當(dāng)我們點擊activity的時候,系統(tǒng)會調(diào)用activity的oncreate()方法,在這個方法中我們會初始化當(dāng)前布局setContentLayout()方法。
onStart()
:onCreate()方法完成后,此時activity進(jìn)入onStart()方法,當(dāng)前activity是用戶可見狀態(tài),但沒有焦點,與用戶不能交互,一般可在當(dāng)前方法做一些動畫的初始化操作
onResume()
:onStart()方法完成之后,此時activity進(jìn)入onResume()方法中,當(dāng)前activity狀態(tài)屬于運行狀態(tài) (Running),可與用戶進(jìn)行交互。
onPause()
:當(dāng)另外一個activity覆蓋當(dāng)前的acitivty時([1]啟動了一個新的Activity [2]返回上一個Activity),此時當(dāng)前activity會進(jìn)入到onPause()方法中,當(dāng)前activity是可見的,但不能與用戶交互狀態(tài)。通常情況下onPause()函數(shù)不會被單獨執(zhí)行,執(zhí)行完onPause()方法后會繼續(xù)執(zhí)行onStop()方法。
onStop()
:onPause()方法完成之后,此時activity進(jìn)入onStop()方法,此時activity對用戶是不可見的,在系統(tǒng)內(nèi)存緊張的情況下,有可能會被系統(tǒng)進(jìn)行回收。所以一般在當(dāng)前方法可做資源回收。(ps:只要activity還可見,就不會調(diào)用onStop,比如下一個開啟的activity是完全透明度)
onDestory()
:onStop()方法完成之后,此時activity進(jìn)入到onDestory()方法中,結(jié)束當(dāng)前activity。
執(zhí)行完onDestory()方法的Activity接下來面對的是被GC回收,宣告生命終結(jié)。
onRestart()
:當(dāng)用戶在其他的Activity或者桌面回切到這個Activity時,這個Activity就會先去執(zhí)行onRestart()函數(shù)。調(diào)用順序onPause()->onStop()->onRestart()->onStart()->onResume().
onCreate和onDestory是配對的,分別標(biāo)識著Activity的創(chuàng)建和銷毀,并且只可能有一次調(diào)用。
從Activity是否可見來說,onStart和onStop是配對的,隨著用戶的操作或者設(shè)備屏幕的點亮和熄滅,這兩個方法可能被調(diào)用多次;
從Activity是否在前臺來說,onResume和onPause是配對的,Activity位于其他 Activity 之前,可與用戶交互并具有輸入焦點。
4.2 Acitivity的異常生命周期
- 橫豎屏切換
當(dāng)Activity處于豎屏狀態(tài),如果突然旋轉(zhuǎn)屏幕,由于系統(tǒng)配置發(fā)生了變化,在默認(rèn)的情況下,Activity會被銷毀并重新創(chuàng)建,當(dāng)然我們可以人為干預(yù)來防止這種情況。
這里有點需要特別注意,onSaveInstanceState和onRestoreInstanceState只有在Activity異常終止時才會被調(diào)用的,正常情況是不會調(diào)用這兩個方法的。
-
內(nèi)存不足導(dǎo)致優(yōu)先級低的 Activity 被殺死
image.png
5. Android的進(jìn)程層次
activity的進(jìn)程優(yōu)先級:前臺進(jìn)程>可見進(jìn)程>service進(jìn)程>后臺進(jìn)程>空進(jìn)程
5.1 前臺進(jìn)程
當(dāng)前進(jìn)程activity正在與用戶進(jìn)行交互。
當(dāng)前進(jìn)程service正在與activity進(jìn)行交互或者當(dāng)前service調(diào)用了startForground()屬于前臺進(jìn)程或者當(dāng)前service正在執(zhí)行生命周期(onCreate(),onStart(),onDestory())
進(jìn)程持有一個BroadcostReceiver,這個BroadcostReceiver正在執(zhí)行onReceive()方法
5.2 可見進(jìn)程
進(jìn)程持有一個activity,這個activity不再前臺,處于onPouse()狀態(tài)下,當(dāng)前覆蓋的activity是以dialog形式存在的。
進(jìn)程有一個service,這個service和一個可見的Activity進(jìn)行綁定。
5.3 service進(jìn)程
當(dāng)前開啟startSerice()啟動一個service服務(wù)就可以認(rèn)為進(jìn)程是一個服務(wù)進(jìn)程。
5.4 后臺進(jìn)程
activity的onStop()被調(diào)用,但是onDestroy()沒有調(diào)用的狀態(tài)。該進(jìn)程屬于后臺進(jìn)程。
5.5 空進(jìn)程
進(jìn)程沒有任何運行的數(shù)據(jù)了,且保留在內(nèi)存空間,并沒有被系統(tǒng)killed,屬于空進(jìn)程。該進(jìn)程很容易被殺死。
6. Activity 的四種啟動模式
6.1 Standard 模式
標(biāo)準(zhǔn)模式,也是系統(tǒng)的默認(rèn)模式(可以不指定),在這樣模式下,每啟動一個Activity都會重新創(chuàng)建一個Activity的新實例,并且將其加入任務(wù)棧中,而且完全不會去考慮這個實例是否已存在。
6.2 singleTop 模式
棧頂復(fù)用模式,顧名思義,在這種模式下,如果有新的Activity已經(jīng)存在任務(wù)棧的棧頂,那么此Activity就不會被重新創(chuàng)建新實例,而是復(fù)用已存在任務(wù)棧棧頂?shù)腁ctivity。這里重點是位于棧頂,才會被復(fù)用,如果新的Activity的實例已存在但沒有位于棧頂,那么新的Activity仍然會被重建。
當(dāng)需要新創(chuàng)建的MainActivity位于棧頂時,MainActivity并沒有重新創(chuàng)建。下面我們再來看看新創(chuàng)建的MainActivity沒有位于棧頂?shù)那闆r。
嗯,這就是singTop模式。這種模式通常比較適用于接收到消息后顯示的界面,如qq接收到消息后彈出Activity界面,如果一次來10條消息,總不能一次彈10個Activity,是吧?再比如新聞客戶端收到了100個推送,你每次點一下推送他都會進(jìn)入某個activiy界面(顯示新聞只用一個activity,只是內(nèi)容不同而已),這時也比較適合使用singleTop模式。
6.3 singleTask 模式
棧內(nèi)復(fù)用模式。這是一種單例模式,與singTop點類似,只不過singTop是檢測棧頂元素是否有需要啟動的Activity,而singTask則是檢測整個棧中是否存在當(dāng)前需要啟動的Activity,如果存在就直接將該Activity置于棧頂,并將該Activity以上的Activity都從任務(wù)棧中移出銷毀,同時也會回調(diào)onNewIntent方法。情況如下圖:
從圖中可以看出,當(dāng)我們再次啟動MainActivity時,由于MainActivity位于棧中,所以系統(tǒng)直接將其置于棧頂,并移除其上方的所有Activity。當(dāng)然如果所需要的MainActivity不存在棧中,則會創(chuàng)建新的Activity并添加到棧中。singleTask 模式比較適合應(yīng)用的主界面activity(頻繁使用的主架構(gòu)),可以用于主架構(gòu)的activity,(如新聞,側(cè)滑,應(yīng)用主界面等)里面有好多fragment,一般不會被銷毀,它可以跳轉(zhuǎn)其它的activity 界面再回主架構(gòu)界面,此時其他Activity就銷毀了。當(dāng)然singTask還有一些比較特殊的場景這個我們后面會一一通過情景代碼分析。
6.4 singleInstance 模式
在singleInstance模式下,該Activity在整個android系統(tǒng)內(nèi)存中有且只有一個實例,而且該實例單獨尊享一個Task。換句話說,A應(yīng)用需要啟動的MainActivity 是singleInstance模式,當(dāng)A啟動后,系統(tǒng)會為它創(chuàng)建一個新的任務(wù)棧,然后A單獨在這個新的任務(wù)棧中,如果此時B應(yīng)用也要激活MainActivity,由于棧內(nèi)復(fù)用的特性,則不會重新創(chuàng)建,而是兩個應(yīng)用共享一個Activity的實例。如下圖所示:
從圖中我們可以看到最終AB應(yīng)用都共享一個singleInstance模式的MainActivity,也沒有去重新創(chuàng)建。
ps
:啟動 Activity 時,先看是否已經(jīng)存在它需要的棧,沒有則創(chuàng)建一個空棧,再在該棧中添加該 Activity 組件。比如在標(biāo)準(zhǔn)模式下,點開 app,啟動根 Activity,是沒有已經(jīng)存在的棧,就創(chuàng)建一個棧,并向該棧中添加根 Activity 組件,此時再從根 Activity 啟動另一個 ActivityB,對于B來說已經(jīng)它需要的棧(即剛才存放根 Activity 的棧),就不用再重新創(chuàng)建棧了。但是如果將 ActivityB 的啟動模式改成singleInstancce,則需要再重新創(chuàng)建一個棧
7.設(shè)置 Activity 的啟動方式
7.1通過AndroidMenifest.xml文件為Activity指定啟動模式
<activity android:name=".ActivityC"
android:launchMode="singleTask" />
7.2 通過在Intent中設(shè)置標(biāo)志位(addFlags方法)來為Activity指定啟動模式
Intent.FLAG_ACTIVITY_SINGLE_TOP 該標(biāo)志位表示使用singleTop模式來啟動一個Activity,與在清單文件指定android:launchMode="singleTop"效果相同。
Intent.FLAG_ACTIVITY_CLEAR_TOP 該標(biāo)志位表示使用singleTask模式來啟動一個Activity,與在清單文件指定android:launchMode="singleTask"效果相同。
Intent.FLAG_ACTIVITY_NO_HISTORY 使用該模式來啟動Activity,當(dāng)該Activity啟動其他Activity后,該Activity就被銷毀了,不會保留在任務(wù)棧中。如A-B,B中以這種模式啟動C,C再啟動D,則任務(wù)棧只有ABD。
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 使用該標(biāo)識位啟動的Activity不添加到最近應(yīng)用列表,也即我們從最近應(yīng)用里面查看不到我們啟動的這個activity。與屬性android:excludeFromRecents="true"效果相同。
Intent intent = new Intent();
intent.setClass(ActivityB.this,ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
注
第2種指定方式的優(yōu)先級高,同時存在時,以第2種為準(zhǔn)。
思考問題
- 問題1
ABCD四個Activity的啟動模式均為SingleTask。此時,先啟動CD再啟動AB,之后由B啟動D。請問現(xiàn)在的后退列表是什么樣子的?
按照DCBA的順序退出
- 問題2
ABCD四個Activity的啟動模式均為SingleTask。此時,先啟動CD再啟動AB,之后由B啟動C。請問現(xiàn)在的后退列表是什么樣子的?
按照CBA的順序退出