Activity是一個(gè)應(yīng)用組件, 單個(gè)的Activity代表一個(gè)單獨(dú)的屏幕界面,用戶可與其提供的屏幕進(jìn)行交互。
一、任務(wù)和返回棧
一個(gè)應(yīng)用通常包含多個(gè)Activity,Android系統(tǒng)使用任務(wù)(Task)來(lái)管理這些Activity,一個(gè)任務(wù)就是一組存放在棧里的Activity的集合,這個(gè)棧也叫做返回棧,Activity 按照各自的打開(kāi)順序排列在棧(即返回棧)中。
任務(wù)(Task)是可以跨應(yīng)用的,這正是任務(wù)存在的一個(gè)重要原因。有的Activity,雖然不在同一個(gè)應(yīng)用中,但為了保持用戶操作的連貫性,把他們放在同一個(gè)任務(wù)中。例如,在我們的應(yīng)用中的一個(gè)Activity A中點(diǎn)擊發(fā)送郵件,會(huì)啟動(dòng)郵件程序的一個(gè)Activity B來(lái)發(fā)送郵件,這兩個(gè)activity是存在于不同應(yīng)用中的,但是被系統(tǒng)放在一個(gè)任務(wù)中,這樣當(dāng)發(fā)送完郵件后,用戶按back鍵返回,可以返回到原來(lái)的Activity A中,這樣就確保了用戶體驗(yàn)。

我們知道,棧是一種“后進(jìn)先出”的數(shù)據(jù)結(jié)構(gòu),默認(rèn)情況下,每創(chuàng)建一個(gè)新的Activity,它會(huì)在返回棧中入棧,并處于棧頂位置。當(dāng)我們按下返回按鈕或者調(diào)用finish()銷毀棧頂活動(dòng)時(shí),位于棧頂?shù)幕顒?dòng)出棧,前一個(gè)棧即成為新的棧頂。系統(tǒng)總是會(huì)顯示處于棧頂?shù)腁ctivity給用戶。
二、Activity 生命周期
(1)Activity的四種狀態(tài)
Activity在其生命周期中最多有四種狀態(tài):
- 運(yùn)行狀態(tài)
當(dāng)一個(gè)Activity位于返回棧的棧頂時(shí),該Activity就處于運(yùn)行狀態(tài)。 - 暫停狀態(tài)
當(dāng)一個(gè)Activity不處于棧頂位置但仍可見(jiàn)時(shí),該Activity就處于暫停狀態(tài)。例如,若一個(gè)Activity被一個(gè)彈出的未占滿屏幕的對(duì)話框Activity遮住了,但是未完全遮住,則此時(shí)該Activity就處于暫停狀態(tài) - 停止?fàn)顟B(tài)
當(dāng)一個(gè)Activity不再處于棧頂位置且完全不可見(jiàn)時(shí),該Activity就處于停止?fàn)顟B(tài) - 銷毀狀態(tài)
當(dāng)一個(gè)Activity從返回棧中移除后就進(jìn)入了銷毀狀態(tài)。
以上四種狀態(tài)的Activity,為了保證手機(jī)內(nèi)存充足,系統(tǒng)最傾向于回收銷毀狀態(tài)的Activity,其次是處于停止?fàn)顟B(tài)的Activity,對(duì)于可見(jiàn)狀態(tài)(暫停狀態(tài)和運(yùn)行狀態(tài))的Activity,只有在內(nèi)存極低的情況下系統(tǒng)才會(huì)考慮回收,且系統(tǒng)最不愿意回收處于運(yùn)行狀態(tài)的Activity,因?yàn)榇藭r(shí)的Activity正與用戶直接交互,若強(qiáng)行回收會(huì)帶來(lái)極差的用戶體驗(yàn)。
(2)Activity的七種回調(diào)方法

如上圖所示,Activity類定義了七個(gè)回調(diào)方法來(lái)表示Activity生命周期的不同環(huán)節(jié):
- onCreate()
在Activity第一次被創(chuàng)建的時(shí)候調(diào)用。 - onStart()
當(dāng)Activity由不可見(jiàn)變?yōu)榭梢?jiàn)狀態(tài)時(shí)調(diào)用。 - onResume()
當(dāng)Activity準(zhǔn)備好與用戶進(jìn)行交互時(shí)調(diào)用。此時(shí)活動(dòng)一定處于運(yùn)行狀態(tài),且位于返回棧棧頂。 - onPause()
在系統(tǒng)準(zhǔn)備去啟動(dòng)或者恢復(fù)另一個(gè)Activity時(shí)調(diào)用。該方法一般用于保存一些關(guān)鍵數(shù)據(jù)以及釋放掉一些消耗CPU的資源。 - onStop()
在Activity完全不可見(jiàn)時(shí)調(diào)用。 - onDestory()
在Activity被銷毀之前調(diào)用。之后Activity即變?yōu)殇N毀狀態(tài)。 - onRestart()
在Activity由停止?fàn)顟B(tài)變?yōu)檫\(yùn)行狀態(tài)之前調(diào)用,也即Activity被重新啟動(dòng)了
(3)Activity的三種生存期
以上七個(gè)方法中,出了onRestart()方法,其他方法都是兩兩對(duì)應(yīng)的,我們可以將Activity分為三種生存期:
(1)完整生存期:onCreate()<-->onDestory()
(2)可見(jiàn)生存期:onStart()<-->onStop()
(3)前臺(tái)生存期:onResume()<-->onPause()
(4)Activity的幾種典型生命周期變化
我總結(jié)了幾種典型情況下Activity的生命周期的變化:
- Activity第一次被創(chuàng)建時(shí)依次執(zhí)行:
onCreate()-->onStart()-->onResume() - Activity被另一個(gè)Activity遮擋時(shí)(完全遮擋)依次執(zhí)行:
onPause()-->onStop() - 然后按下back鍵返回上一個(gè)Activity:
onRestart()-->onStart()-->onResume() - 打開(kāi)另一個(gè)對(duì)話框形式的Activity(部分遮擋):
onPause()-->按下back鍵返回-->onResume() - 按下back鍵退出程序:
onPause()-->onStop()-->onDestroy()
(5)Activity被回收的處理
在 Activity 生命周期中,Android 會(huì)在銷毀 Activity 之前調(diào)用onSaveInstanceState(),以便保存有關(guān)應(yīng)用狀態(tài)的數(shù)據(jù)。
@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("message", text.getText().toString());
}
我們可以在onCreate()中取出Activity銷毀之前保存的數(shù)據(jù)來(lái)恢復(fù) Activity 狀態(tài)。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null)
{
String message = savedInstanceState.getString("message");
}
}
除了在onCreate()中恢復(fù)外,我們還可以使用onRestoreInstanceState()函數(shù)來(lái)恢復(fù)數(shù)據(jù),如下所示:
@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
String message = savedInstanceState.getString("message");
}
需要注意的是,onSaveInstanceState()和onRestoreInstanceState()并不同于Activity的生命周期方法,它們并不一定會(huì)被觸發(fā)。
例如,當(dāng)應(yīng)用遇到意外情況(如:內(nèi)存不足、用戶直接按Home鍵)由系統(tǒng)銷毀一個(gè)Activity時(shí),onSaveInstanceState() 會(huì)被調(diào)用。但是當(dāng)用戶主動(dòng)去銷毀一個(gè)Activity時(shí),例如在應(yīng)用中按返回鍵,onSaveInstanceState()就不會(huì)被調(diào)用。因?yàn)樵谶@種情況下,用戶的行為決定了不需要保存Activity的狀態(tài)。
而onRestoreInstanceState()被調(diào)用的前提是,Activity確實(shí)被系統(tǒng)銷毀了,而不是有可能被銷毀。例如,當(dāng)正在顯示activity A的時(shí)候,用戶按下HOME鍵回到主界面,然后用戶緊接著又返回到Activity A,這種情況下Activity A一般不會(huì)因?yàn)閮?nèi)存的原因被系統(tǒng)銷毀,故Activity A的onRestoreInstanceState()方法不會(huì)被執(zhí)行。
通常onSaveInstanceState()只適合用于保存一些臨時(shí)性的狀態(tài),而onPause()適合用于數(shù)據(jù)的持久化保存。
三、Activity的啟動(dòng)模式
Activity有四種啟動(dòng)模式,分別為standard,singleTop,singleTask,singleInstance。如果要使用這四種啟動(dòng)模式,必須在manifest文件中<activity>標(biāo)簽中的launchMode屬性中配置,如下所示,若不配置的話,默認(rèn)為standard模式:
<activity android:name=".MainActivity"
android:label="@string/title_name"
android:theme="@android:style/Theme.Holo.Light"
android:launchMode="singleTask"
</activity>
- standard 標(biāo)準(zhǔn)模式,每次都新建一個(gè)實(shí)例對(duì)象
- singleTop 如果在任務(wù)棧頂發(fā)現(xiàn)了相同的實(shí)例(注意是棧頂),則調(diào)用原來(lái)?xiàng)m攲?shí)例的onNewIntent()方法來(lái)重用該實(shí)例,而不是新建一個(gè)實(shí)例。否則新建并壓入棧頂
- singleTask 如果在任務(wù)棧中發(fā)現(xiàn)了相同的實(shí)例,將其上面的任務(wù)終止并移除,重用該實(shí)例。否則新建實(shí)例并入棧
- singleInstance 允許不同應(yīng)用,進(jìn)程線程等共用一個(gè)實(shí)例,無(wú)論從何應(yīng)用調(diào)用該實(shí)例都重用
為了便于理解,特意畫了幾張示意圖說(shuō)明:
(1)standard:每次激活A(yù)ctivity時(shí)(startActivity),都創(chuàng)建Activity實(shí)例,并放入任務(wù)棧。

從圖中可以看出,雖然當(dāng)前棧頂為Activty2,但若再開(kāi)啟一個(gè)Activity2仍然會(huì)新建一個(gè)實(shí)例壓入棧中成為新的棧頂。這種模式其實(shí)并不合理,每次都新建一個(gè)實(shí)例實(shí)在是浪費(fèi)。事實(shí)上,我們可以根據(jù)實(shí)際情況采用下面的三種方式來(lái)進(jìn)行優(yōu)化。
(2)singleTop:如果某個(gè)Activity自己激活自己,即任務(wù)棧棧頂就是該Activity,則不需要?jiǎng)?chuàng)建,其余情況都要?jiǎng)?chuàng)建Activity實(shí)例。

采用這種模式可以很好地解決重復(fù)棧頂?shù)膯?wèn)題,但是若活動(dòng)并不處于棧頂,還是會(huì)重復(fù)創(chuàng)建多個(gè)實(shí)例。有沒(méi)有辦法可以讓整個(gè)應(yīng)用程序的上下文只存在某個(gè)Activity的一個(gè)實(shí)例呢?這就要用到singleTask模式了。
(3)singleTask:如果要激活的那個(gè)Activity在任務(wù)棧中存在該實(shí)例,則不需要?jiǎng)?chuàng)建,只需要把此Activity放入棧頂,并把該Activity以上的Activity實(shí)例都從棧中移除。

從上圖中可以看到,當(dāng)前棧頂為Activity3,開(kāi)啟Activity1,此時(shí)棧中存在Activity1,則將Activity1上面的Activity3、Activity2移除,使Activity1成為新的棧頂。
singleTop和singleTask看起來(lái)已經(jīng)可以解決大部分重復(fù)創(chuàng)建實(shí)例的問(wèn)題了。但是,若某個(gè)應(yīng)用的某個(gè)Activity頻繁被其他應(yīng)用調(diào)用,那么情況又會(huì)怎樣呢?我們知道,每個(gè)應(yīng)用都會(huì)有自己的返回棧,同一個(gè)Activity被不同應(yīng)用調(diào)用,必然會(huì)在不同應(yīng)用的返回棧中都創(chuàng)建新的實(shí)例,而使用singleInstance就可以解決這個(gè)問(wèn)題了。
(4)singleInstance:如果應(yīng)用1的任務(wù)棧中創(chuàng)建了MainActivity實(shí)例,如果應(yīng)用2也要激活MainActivity,則不需要?jiǎng)?chuàng)建,兩應(yīng)用共享該Activity實(shí)例;

從上圖中可以看到,Activity3存放在一個(gè)單獨(dú)的返回棧里,在singleInstance中,會(huì)有一個(gè)單獨(dú)的返回棧來(lái)管理某個(gè)被其他應(yīng)用頻繁調(diào)用的Activity,不管哪個(gè)應(yīng)用來(lái)訪問(wèn)這個(gè)Activity,都共用同一個(gè)返回棧,這也就解決了應(yīng)用間共享Activity實(shí)例的問(wèn)題。