欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Activity生命周期與啟動(dòng)模式圖文解說(shuō)

 更新時(shí)間:2017年11月25日 09:17:09   作者:明立  
這篇文章主要介紹了Activity生命周期與啟動(dòng)模式圖文解說(shuō),內(nèi)容比較詳細(xì),具有一定參考價(jià)值,需要的朋友可以了解下。

Activity作為Android開(kāi)發(fā)中最常用的一個(gè)組件,是Android開(kāi)發(fā)人員必須熟悉且掌握的重要內(nèi)容。同時(shí)Activity也是在面試中經(jīng)常被問(wèn)到的一個(gè)方向。因此,掌握Activity的重要性也不言而喻。希望能夠?qū)ctivity有一個(gè)較為全面的介紹。如果在閱讀過(guò)程中發(fā)現(xiàn)講述的內(nèi)容中有什么疏忽沒(méi)有記錄下來(lái)或者是錯(cuò)誤的地方的話,歡迎在下方留言指出。下面開(kāi)始進(jìn)入正題吧:

預(yù)備知識(shí):任務(wù)棧/回退棧**

棧是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),具有先進(jìn)后出,后進(jìn)先出的特點(diǎn)。從數(shù)據(jù)形式上來(lái)說(shuō),它可以用下面這一張圖來(lái)表示:

在這個(gè)棧中,我們每一個(gè)新放進(jìn)棧的數(shù)據(jù),都會(huì)放在棧頭的位置,而其他的在之前如果已經(jīng)放進(jìn)來(lái)的數(shù)據(jù),則會(huì)被逐漸按順序往棧底下面移動(dòng),看起來(lái)就像是前面先被進(jìn)來(lái)的數(shù)據(jù)被后面新放進(jìn)來(lái)的數(shù)據(jù)往棧底下面壓一樣。這種情況叫做壓棧。就好像一把手槍的彈夾,當(dāng)我們把里面裝子彈的時(shí)候,后面放進(jìn)去的子彈會(huì)被逐漸往底部擠壓下去。而當(dāng)我們需要取出數(shù)據(jù)時(shí),因?yàn)闂>鸵?guī)定了一個(gè)進(jìn)出口,就是棧頭(也叫棧頂),所以我們?nèi)〕鰯?shù)據(jù)的時(shí)候,也是要按照數(shù)據(jù)進(jìn)來(lái)的順序,從棧頂開(kāi)始取出,每取出一個(gè)順序,棧中的其他數(shù)據(jù)就會(huì)忘上移,直到最后一個(gè)數(shù)據(jù)從棧頂被取出而結(jié)束。這種情況叫做彈棧。而如果我們不想要其他的數(shù)據(jù),值需要棧中倒數(shù)第二個(gè)數(shù)據(jù)的話,那也沒(méi)辦法,只能把這個(gè)數(shù)據(jù)前面的數(shù)據(jù)全部彈出棧,你才能取到這個(gè)數(shù)據(jù)。否則的話一切皆是免談。而在Android的設(shè)計(jì)中,是使用棧這種數(shù)據(jù)結(jié)構(gòu)來(lái)存放Activity的,它有一個(gè)名字,叫做任務(wù)棧,也叫回退棧。關(guān)于棧的知識(shí),到這里已經(jīng)基本可以用來(lái)介紹Activity了,至于其他方面的內(nèi)容,可參考其他博客或書籍。這里推薦的是:程杰的《大話數(shù)據(jù)結(jié)構(gòu)》一書。

什么是Activity:

Activity生命周期經(jīng)典圖解:

Activity,中文“活動(dòng)”。在任大神的書中,把它理解成界面。實(shí)際上我非常同意這種說(shuō)法,因?yàn)锳ctivity實(shí)際上就是我們?cè)趹?yīng)用中展現(xiàn)出來(lái)的一個(gè)個(gè)用戶界面,它會(huì)加載指定的布局文件來(lái)顯示各種UI元素,并為這些元素設(shè)置事件處理函數(shù),從而實(shí)現(xiàn)用戶與應(yīng)用的交互。比如我們打開(kāi)一個(gè)手機(jī)App時(shí),展現(xiàn)出來(lái)的登錄界面、注冊(cè)界面、主界面等,都是一個(gè)個(gè)不同的Activity。它是用戶可以直接在App上用肉眼看得到的界面操作,以及針對(duì)用戶對(duì)App的某些特定操作而進(jìn)行的事件處理(這個(gè)是用戶不可見(jiàn)的)。

Activity的組成:

在上面對(duì)Activity的介紹中,用以作為用戶可見(jiàn)的部分顯示的是一份.xml格式的布局文件,而用以布置事件處理函數(shù)的則是一個(gè)Activity對(duì)象。那么為什么我們把肉眼可見(jiàn)的部分也叫作Activity呢?因?yàn)槲覀兛梢灾苯釉贏ctivity中對(duì)布局文件進(jìn)行操作,等于布局文件是Activity對(duì)象的一個(gè)外延,但多數(shù)情況下,我們使用Activity的方式依舊為Activity對(duì)象+xml布局文件。不過(guò),關(guān)于Activity的組成,卻并沒(méi)有那么簡(jiǎn)單。實(shí)際上,一個(gè)完整的Activity組成并沒(méi)有那么簡(jiǎn)單,在Activity與開(kāi)發(fā)人員可以設(shè)置的視圖,也就是對(duì)用戶界面進(jìn)行布局的范圍之上,還包括了其他層次的封裝。如圖:

我們可以看到,在Activity之下有一個(gè)PhoneWindow,這個(gè)PhoneWindow實(shí)際上是一個(gè)叫做Window的類的實(shí)現(xiàn)類。說(shuō)起Window,相信有人試過(guò)在取消Activity自帶的標(biāo)題欄的時(shí)候,調(diào)用了這么一個(gè)方法:

//取消系統(tǒng)自帶的標(biāo)題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);

而這個(gè)方法的具體模樣,是這樣的:

 public final boolean requestWindowFeature(int featureId) {
    return getWindow().requestFeature(featureId);
  }

我們發(fā)現(xiàn),它實(shí)際回調(diào)了一個(gè)getWindow().requestFeature(featureId)方法,而這個(gè)getWindow()返回的實(shí)際上就是一個(gè)Window類型的對(duì)象mWindow:

public Window getWindow() {
    return mWindow;
  }

那么,當(dāng)我們查看這個(gè)Window源碼的時(shí)候,發(fā)現(xiàn)它其實(shí)是抽象類

public abstract class Window {
  /** Flag for the "options panel" feature. This is enabled by default. */
  public static final int FEATURE_OPTIONS_PANEL = 0;
  /** Flag for the "no title" feature, turning off the title at the top
   * of the screen. */
  public static final int FEATURE_NO_TITLE = 1;
  /** Flag for the progress indicator feature */
  public static final int FEATURE_PROGRESS = 2;
  /** Flag for having an icon on the left side of the title bar */
  .....
}

我們知道,抽象類要想發(fā)揮作用,那么需要有一個(gè)子類去繼承抽象類,而PhoneWinsow這是這么一個(gè)實(shí)現(xiàn)類。我們所執(zhí)行的去除標(biāo)題欄的操作,實(shí)際上調(diào)用的也是這個(gè)PhoneWindow中的方法而已。這也從側(cè)面反映出我們前面所說(shuō)的,Activity的組成不僅僅是一個(gè)Activity對(duì)象+xml布局文件那么簡(jiǎn)單。盡管我們常見(jiàn)的模式就是這樣,但實(shí)際上這已經(jīng)是經(jīng)過(guò)封裝之后才展現(xiàn)出來(lái)的。

Activity的創(chuàng)建、激活與銷毀

創(chuàng)建Activity

要在代碼中創(chuàng)建一個(gè)Activity,需要經(jīng)過(guò)一下幾個(gè)步驟:
1.新建一個(gè)類,繼承自android.app.Activity.類的命名建議為:xxxActivity樣式,比如LoginActivity
2.在AndroidManifest.xml文件中的 < application>節(jié)點(diǎn)下使用新的< activity>節(jié)點(diǎn)注冊(cè)該Activity,同時(shí)為< activity>節(jié)點(diǎn)配置android:name屬性.取值為Activity類的包名和類名,推薦為每一個(gè)< activity>節(jié)點(diǎn)配置android:label屬性。例如:

<activity
   android:name=".LoginActivity"
   android:label="@string/title_activity_login" >
 </activity>

注意:如果存在多個(gè)Activity,那么各< activity>節(jié)點(diǎn)不區(qū)分先后順序。如果要調(diào)整第一個(gè)進(jìn)入軟件顯示界面的Activity,那么則需在該< activity>節(jié)點(diǎn)中配置以下信息:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>

3.如果需要在Activity中加入xml布局文件,則需要在res\layout目錄下創(chuàng)建并設(shè)計(jì)布局,命名建議為activity_xxx(與xxxActivity匹配),如activity_login。
4.設(shè)計(jì)完布局文件之后,在Activity類中重寫onCreate()方法,并在該方法中通過(guò)調(diào)用setContentView()方法加載布局。比如:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_registe
  }

以上為手動(dòng)創(chuàng)建Activity的方式,當(dāng)然我們也可以使用IDE幫助實(shí)現(xiàn)。以Eclipse為例:
1.快捷鍵:ztrl+N。彈出窗口如下:

選擇Android目錄下-> Android Activity ,點(diǎn)擊Next,效果如下:

選擇樣式,這里選擇默認(rèn)樣式Black Activity。點(diǎn)擊next,效果如下:

在這里,更改Activity Name欄目,下面Layout欄目也會(huì)發(fā)生自動(dòng)變化,點(diǎn)擊finish。創(chuàng)建成功。

激活A(yù)ctivity

我們創(chuàng)建了Activity之后,除非把它設(shè)置為默認(rèn)界面,否則都需要被激活才可使用。調(diào)用Activity類定義的startActivity(Intent)方法,即可激活新的Activity,其中:參數(shù)Intent對(duì)象可以直接通過(guò)Intent類的構(gòu)造方法來(lái)創(chuàng)建
在使用Intent類的構(gòu)造方法時(shí),指定2個(gè)參數(shù),第1個(gè)參數(shù)是Context對(duì)象
第2個(gè)參數(shù)是被激活的Activity類,例如SecondActivity.class。例子如下:

//跳轉(zhuǎn)到另一個(gè)Activity
startActivity(new Intent(this,SecondActivity.class));

如此,便實(shí)現(xiàn)了激活SecondActivity并跳轉(zhuǎn)至SecondActivity界面的操作

上面是激活A(yù)ctivity的第一種方法,而如果你需要在激活第二個(gè)Activity后對(duì)其設(shè)置,并且在該Activity執(zhí)行finish之后返回?cái)?shù)據(jù)給第一個(gè)Activity的時(shí)候,可以用startActivityForResult()方法。用法如下:

Intent mIntent =new Intent(this,SecondActivity.class);
int requestCode = 0;
startActivityForResult(mIntent,requestCode)

同時(shí),在第一個(gè)Activity重寫數(shù)據(jù)返回的處理辦法onActivityResult();用法如下:

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 

}

注意:requestCode可以隨便設(shè)置,但必須大于或等于0

銷毀Activity

調(diào)用Activity類定義的finish()方法即可銷毀當(dāng)前Activity。

Activity的生命周期分析:

典型情況下的生命周期分析

在正常情況下。Activity會(huì)經(jīng)歷以下生命周期,每個(gè)生命周期都執(zhí)行著一個(gè)聲明周期方法:

1.onCreate():在我們前面的手動(dòng)創(chuàng)建Activity的例子中便已經(jīng)接觸到這個(gè)方法,它是Activity生命周期執(zhí)行的第一個(gè)生命周期方法,表示的是Activity正在被創(chuàng)建,在這個(gè)生命周期方法里我們可以執(zhí)行一些初始化的工作。比如加載xml布局文件,初始化元素控件以及加載相應(yīng)的數(shù)據(jù)或者設(shè)置監(jiān)聽(tīng)器等。

2.onStart():表示Activity正在啟動(dòng),并且逐漸從不可見(jiàn)到可見(jiàn)直到Activity展示到前臺(tái)

3.onRestart():表示Activity正在重啟。一般情況下,當(dāng)當(dāng)前的Activity由不可見(jiàn)狀態(tài)重新恢復(fù)為可見(jiàn)狀態(tài)的過(guò)程中,就會(huì)調(diào)用這個(gè)方法。

4.onResume():在Activity徹底展示在前臺(tái)(完全可見(jiàn))的時(shí)候被調(diào)用,在執(zhí)行完這個(gè)方法后,Activity會(huì)請(qǐng)求ActivityManagerService(下稱AMS)對(duì)它管理的視圖進(jìn)行渲染,此時(shí)的Activity位于棧頂且保持運(yùn)行狀態(tài)

5.onPause():該方法在Activity由可見(jiàn)狀態(tài)逐漸變?yōu)椴豢梢?jiàn)的狀態(tài)的過(guò)程中調(diào)用。一般在系統(tǒng)準(zhǔn)備去啟動(dòng)或者恢復(fù)另一個(gè)Activity的時(shí)候調(diào)用。這時(shí)可做一些數(shù)據(jù)存儲(chǔ)、停止動(dòng)畫或者釋放一些消耗的CPU資源等操作,但注意不要做耗時(shí)操作。否則會(huì)造成卡頓現(xiàn)象或者ActiviNotResponding異常(ANR)。

6.onStop():表示Activity處于停止,即完全不可見(jiàn)狀態(tài)。

7.onDestory():在Activity被徹底銷毀之前調(diào)用,表示著Activity被徹底移出了任務(wù)棧。是Activity的最后一個(gè)聲明周期方法。

關(guān)于Activity的生命周期,網(wǎng)上找了一張非常明了的示意圖:

在這里作兩點(diǎn)補(bǔ)充關(guān)于從onPause()–>onStop()的特例:
1.如書中所言,當(dāng)新的Activity采用的是透明主題是,Activity不回調(diào)onStop()方法
2.當(dāng)新啟動(dòng)的Activity是一個(gè)對(duì)話框式的Activity,那么onStop()方法同樣不會(huì)被回調(diào)。

關(guān)于書中提出的兩個(gè)問(wèn)題,結(jié)合大神的解釋和自己的一些想法,歸納如下:

問(wèn)題1:onStart和onResume、onPause和onStop從描述上差不多,對(duì)我們來(lái)說(shuō)有什么區(qū)別呢?

大神的解釋:onStart和onStop是從Activity是否可見(jiàn)的角度進(jìn)行回調(diào)的。而onResume和onPause是否位于前臺(tái)這個(gè)角度來(lái)回調(diào)的。在實(shí)際開(kāi)發(fā)中沒(méi)有其他明顯區(qū)別。
我的想法:onStart和onPause對(duì)應(yīng)的是一種動(dòng)態(tài)的變化,前者是從不可見(jiàn)到逐漸可見(jiàn)再到完全可見(jiàn)(onResume)的變化。而后者則是從完全可見(jiàn)到逐漸不可見(jiàn)再到完全不可見(jiàn)的狀態(tài)(onStop)。相應(yīng)的,onResume和onStop對(duì)應(yīng)的就是一個(gè)靜態(tài)改變。一旦完全可見(jiàn),立刻調(diào)用onResume,一旦不可見(jiàn),立刻調(diào)用onStop。這也是為什么當(dāng)新建的 Activity為透明主題時(shí),onStop方法不會(huì)被回調(diào)。因?yàn)閺那芭_(tái),也就是顯示界面的窗口來(lái)看,Activity并沒(méi)有從窗口中消除,依舊為可見(jiàn)狀態(tài),只是這個(gè)Activity不能控制而已。

問(wèn)題2:假設(shè)當(dāng)前Activity為A,如果這時(shí)用戶打開(kāi)一個(gè)新的ActivityB,那么B的onResume和A的onPause哪個(gè)先執(zhí)行呢?

大神的解釋:從源碼分析角度來(lái)看,當(dāng)我們要啟動(dòng)一個(gè)Activity時(shí),啟動(dòng)Activity的請(qǐng)求會(huì)由Instrumentation來(lái)處理,然后它通過(guò)Bilder像AMS發(fā)送一個(gè)請(qǐng)求,而AMS內(nèi)部維護(hù)著一個(gè)ActivityStack(任務(wù)棧),負(fù)責(zé)的是棧內(nèi)的Activity的狀態(tài)同步,AMS通過(guò)ActivityThread去同步Activity的狀態(tài)從而完成生命周期的調(diào)用。在ActivityStack的源碼中,確定了新的Activity啟動(dòng)之前,棧頂?shù)腁ctivity要先onPause后,在ActivityStackSupervisor中的realStartActivityLocked方法調(diào)用scheduleLauchActivity方法來(lái)完成新Activity的onCreate、onStart、onResume的調(diào)用過(guò)程。
我的想法:從生命周期的作用描述來(lái)看,當(dāng)我們要啟動(dòng)一個(gè)ActivityB并且在它由不可見(jiàn)到逐漸可見(jiàn)再到完全可見(jiàn)的過(guò)程中,無(wú)可避免的是會(huì)占用前臺(tái)顯示的空間,也就是說(shuō)在這個(gè)過(guò)程中,會(huì)使得ActivityA失去完全可見(jiàn)的狀態(tài),變成局部可見(jiàn)或者逐漸不可見(jiàn)的狀態(tài),而在這時(shí)候,就已經(jīng)調(diào)用了A的onPause方法,而當(dāng)B的onResume方法被調(diào)用時(shí),如果B不是透明主題或者對(duì)話框式的Activity的話,這個(gè)時(shí)候A的onStop也會(huì)開(kāi)始被調(diào)用。即:先調(diào)用A的onPause,再調(diào)用B的onResume.

ps:自主想法,未經(jīng)推敲,如果有發(fā)現(xiàn)不妥的地方,可在下方評(píng)論指出,以便及時(shí)更改。

異常情況下的生命周期分析

關(guān)于異常情況下的生命周期分析,大神主要講了兩種情況:

1.資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重新創(chuàng)建

在發(fā)生因?yàn)橄到y(tǒng)配置突然發(fā)生改變,需要立即殺死當(dāng)前的Activity并且重新創(chuàng)建,就如手機(jī)突然旋轉(zhuǎn)屏幕,需要重新加載適應(yīng)屏幕變化的Activity的時(shí)候。Activity的生命周期如圖所示:

在Activity被異常關(guān)閉并且需要重新恢復(fù)的時(shí)候,Activity會(huì)先被徹底銷毀,其onPause、onStop、onDestroy方法都會(huì)被調(diào)用。之后才再重新開(kāi)始調(diào)用onCreate方法。但因?yàn)槭钱惓jP(guān)閉,在恢復(fù)Activity時(shí)我們也不希望看到數(shù)據(jù)丟失的情況。于是在Activity的onStop方法被調(diào)用前,會(huì)執(zhí)行onSaveInstanceState方法保存Activity內(nèi)的數(shù)據(jù),在新恢復(fù)的Activity調(diào)用onRestoreInstanceState方法,并且把Activity銷毀前調(diào)用onSaveInstanceState方法所保存的Bundle對(duì)象作為參數(shù)同時(shí)傳遞給onCreate和onRestoreInstanceState方法,通過(guò)兩者的信息對(duì)比來(lái)判斷是否重建,如果確定是重建了,則取出之前保存的數(shù)據(jù)并且恢復(fù),這個(gè)過(guò)程出現(xiàn)在onStart之前。
而關(guān)于數(shù)據(jù)恢復(fù)的過(guò)程,工作流程如下:
1.Activity調(diào)用onSaveInstanceState保存數(shù)據(jù)
2.Activity委托Window去幫忙保存數(shù)據(jù),就好像自己死前把信物交給信得過(guò)的人一般
3.Window在委托它的上層頂級(jí)容器取保存數(shù)據(jù),這個(gè)容器是一個(gè)ViewGroup,在Activity中可能就是DecorView
4.頂層容器通知它的子元素來(lái)保存相關(guān)數(shù)據(jù)。
5.完成

注:當(dāng)Activity正常銷毀時(shí),系統(tǒng)不會(huì)調(diào)用onSaveInstanceState方法來(lái)保存數(shù)據(jù),只有在Activity異常終止的并且有機(jī)會(huì)重新顯示的情況下才會(huì)調(diào)用onSaveInstanceState方法。

2.資源內(nèi)存不足導(dǎo)致低優(yōu)先級(jí)的Activity被殺死

這種情況下,數(shù)據(jù)存儲(chǔ)和恢復(fù)過(guò)程和情況1是一樣的。但是這里做個(gè)區(qū)分,在手機(jī)內(nèi)存不足的時(shí)候,有時(shí)候我們把應(yīng)用退出到后臺(tái),過(guò)了一會(huì)再打開(kāi)的時(shí)候,發(fā)現(xiàn)它是重新啟動(dòng)了應(yīng)用,而不是像情況2說(shuō)的會(huì)恢復(fù)。因?yàn)樵谶@里涉及到的并不是情況2,事實(shí)上,情況2針對(duì)的是Activity,是指應(yīng)用在執(zhí)行過(guò)程中處于后臺(tái)的Activity被kill(殺死)。而上面所說(shuō)的則是手機(jī)在整個(gè)應(yīng)用處于后臺(tái)的時(shí)候,直接把整個(gè)應(yīng)用銷毀掉,這屬于典型的生命周期調(diào)度過(guò)程(參見(jiàn)示意圖左側(cè))。

下面記錄Activity的優(yōu)先級(jí)情況,也就是當(dāng)內(nèi)存不足時(shí),系統(tǒng)會(huì)根據(jù)Activity的優(yōu)先級(jí)從低到高kill掉一些不需要的Activity以釋放資源工其他Activity調(diào)用。
1.前臺(tái)Activity,正在和用戶的交互的Activity,一般為用戶對(duì)可控UI元素具有操作的能力。比如,點(diǎn)擊按鈕有反應(yīng)。優(yōu)先級(jí)最高。
2.可見(jiàn)但非前臺(tái)Actiyity,比如Activity彈出了一個(gè)對(duì)話框,導(dǎo)致Activity可以可見(jiàn),但是對(duì)控件不具有操作的能力,只能在對(duì)話框中進(jìn)行交互,優(yōu)先級(jí)次之
3.后臺(tái)Activity,位于后臺(tái)的不可見(jiàn)Activity,優(yōu)先級(jí)最低,系統(tǒng)首先清理該部分的Activity。

對(duì)于情況1的一個(gè)拓展:如果想讓系統(tǒng)配置發(fā)生改變后不重新創(chuàng)建,我們可以通過(guò)在 < activity>節(jié)點(diǎn)中設(shè)置 以下的屬性來(lái)實(shí)現(xiàn):

android:configChanges="orientation"

在這里,android:configChanges的作用是捕獲設(shè)備的變化,并回調(diào)相應(yīng)的處理方法而不會(huì)重新恢復(fù)Activity。當(dāng)然,關(guān)于ConfigChanges的屬性值是有很多的,但我們需要定義多個(gè)屬性的時(shí)候,可以用 | 號(hào)分割,比如:

android:configChanges="orientation|keyboardHidden"

而關(guān)于configChages的屬性值及其含義,可以參考如下:

Activity的啟動(dòng)模式:

關(guān)于Activity的啟動(dòng)模式,就要回顧我們的預(yù)備知識(shí)——任務(wù)棧了。在Android中,系統(tǒng)是利用任務(wù)棧來(lái)存儲(chǔ)每次創(chuàng)建的Activity,這就意味著只要有多次重復(fù)調(diào)用同一個(gè)Activity的現(xiàn)象,那么我們就要?jiǎng)?chuàng)建多個(gè)Activity并且把他們存儲(chǔ)到Activity中,這樣不僅浪費(fèi)存儲(chǔ)空間,還使得Activity的回退機(jī)制變得過(guò)于死板,不符合Android靈活開(kāi)發(fā)的需求。于是,Android對(duì)任務(wù)棧就行了一定的功能封裝,形成了四種啟動(dòng)模式:

1.standard(標(biāo)準(zhǔn)模式):這是系統(tǒng)默認(rèn)的啟動(dòng)模式,每創(chuàng)建一個(gè)新的Activity,都會(huì)產(chǎn)生一個(gè)新的Activity實(shí)例并且放入相應(yīng)的任務(wù)棧中。和典型的棧調(diào)用數(shù)據(jù)類似沒(méi)多大區(qū)別。

2.singleTop(棧頂復(fù)用模式,也叫棧頂唯一模式):在這種模式下,如果要新建的Activity本身已經(jīng)有一個(gè)Activity實(shí)例位于棧頂時(shí),那么這個(gè)Activity不會(huì)被重新創(chuàng)建,而是會(huì)回調(diào)onNewIntent方法取出當(dāng)前請(qǐng)求的信息,而這個(gè)新建的Activity不會(huì)被系統(tǒng)調(diào)用onCreate、onStart方法。注意的是,該模式只使用于新Activity已經(jīng)位于棧頂。否則的話還是會(huì)創(chuàng)建新的Activity并且進(jìn)行壓棧操作。

3.singTask(棧內(nèi)復(fù)用模式,也叫任務(wù)唯一模式):在這個(gè)模式下,只要Activity在任務(wù)棧中存在,那么當(dāng)我們新建該Activity時(shí),會(huì)將棧內(nèi)存在的Activity做置頂操作。也就是說(shuō),除非要?jiǎng)?chuàng)建的Activity已經(jīng)位于棧頂,否則系統(tǒng)會(huì)在棧內(nèi)將位于該Activity之上的所有Activity做彈棧操作,直到該Activity位于棧頂。而如果要?jiǎng)?chuàng)建的Activity在棧內(nèi)不存在時(shí),會(huì)直接創(chuàng)建并壓棧。

4.singleInstance(單實(shí)例模式):這是一種加強(qiáng)的singleTask模式,它除了具有singTask的一切特性之外,還加強(qiáng)了一點(diǎn),就是具有此模式的Activity只能單獨(dú)的位于一個(gè)任務(wù)棧中。也就是說(shuō),如果ActivityA是singleInstance模式,在它啟動(dòng)的時(shí)候,系統(tǒng)會(huì)為它分配一個(gè)新的任務(wù)棧。由于singleTask的復(fù)用性,在其他需要?jiǎng)?chuàng)建Activity的時(shí)候,都不會(huì)創(chuàng)建新的Activity。而注意的是,因?yàn)閟ingleInsyance模式所創(chuàng)建的實(shí)例是位于一個(gè)獨(dú)立的任務(wù)棧里,所以當(dāng)我們銷毀Activity的時(shí)候,會(huì)先把棧頂Activity所在的任務(wù)棧里面的Activity清理完畢再來(lái)清理該Activity。例如,Activity的啟動(dòng)順序如下:
A(棧頂)
B(singleInstance)
C
D(棧底)
那么當(dāng)我們連續(xù)按back鍵時(shí),銷毀順序?yàn)?A -> C -> D -> B

askAffinity與Activity的關(guān)系

在講述兩者關(guān)系的時(shí)候,首先可以聲明一下:在Android系統(tǒng)中,并不是只有一個(gè)任務(wù)棧,很多時(shí)候,在每一個(gè)應(yīng)有程序之間都會(huì)存有一個(gè)任務(wù)棧,在這個(gè)應(yīng)用中所創(chuàng)建出來(lái)的Activity,在一般情況下會(huì)放入同應(yīng)用下的任務(wù)棧中,而這個(gè)任務(wù)棧的名字為應(yīng)用的包名。那么,有沒(méi)有特殊情況,我們創(chuàng)建的Activity會(huì)進(jìn)入到其他的任務(wù)棧之中呢?如果可以,它又會(huì)跳轉(zhuǎn)到哪個(gè)任務(wù)棧中呢?我們可以通過(guò)TaskAffinity屬性給出答案。
每一個(gè)Activity都會(huì)有一個(gè)TaskAffinity參數(shù),這個(gè)參數(shù)標(biāo)識(shí)了Activity所需要進(jìn)入的任務(wù)棧的名字。如果我們不對(duì)其進(jìn)行設(shè)置,那么它默認(rèn)為當(dāng)前應(yīng)用的包名,也就是當(dāng)前應(yīng)用下的任務(wù)棧。而如果我們對(duì)其設(shè)置了其他應(yīng)用的包名的話,那么在一些特定情況下,該Activity則會(huì)出現(xiàn)轉(zhuǎn)移的情況,書中介紹了兩種情況:

1.當(dāng)TaskAffinity和singleTask啟動(dòng)模式配對(duì)使用的時(shí)候

如果應(yīng)用要加載singleTask模式的Activity時(shí),首先該Activity會(huì)檢查是否存在與它的taskAffinity相同的任務(wù)棧。如果存在,那么檢查棧內(nèi)是否有已經(jīng)實(shí)例化的Activity,如果有,那么銷毀在該Activity以上的Activity并調(diào)用onNewIntent。如果沒(méi)有,那么該Activity實(shí)例化并入棧。而如果任務(wù)棧不存在,那么將重新創(chuàng)建出一個(gè)任務(wù)棧,并入棧。

2.當(dāng)TaskAffinity與allowTaskReparenting結(jié)合的時(shí)候

在這種情況下,如果該Activity的allowTaskReparenting設(shè)置為true的時(shí)候,這個(gè)Activity會(huì)直接進(jìn)入后臺(tái),直到當(dāng)和TaskAffinity名字相同的任務(wù)棧進(jìn)入前臺(tái)的時(shí)候,此時(shí)的Activity會(huì)轉(zhuǎn)移到該任務(wù)棧中并處于棧頂位置。
書中例子:先有應(yīng)用A、B。當(dāng)在A中啟動(dòng)B的一個(gè)ActivityC,然后按Home鍵回到桌面,打開(kāi)B應(yīng)用。此時(shí)你會(huì)發(fā)現(xiàn)顯示出來(lái)的是ActivityC。

給Activity制定啟動(dòng)模式的方法

1.通過(guò)AndroidMenifest.xml為Activity指定啟動(dòng)模式,在相應(yīng)的節(jié)點(diǎn)中添加屬性:

android:launchMode="launchName"

這里的launchName為四種啟動(dòng)模式任意一種,注意為英文!

2.在Intent中設(shè)置標(biāo)志位來(lái)指定啟動(dòng)模式。比如:

Intent intent =new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

注:當(dāng)兩種方法同時(shí)應(yīng)用時(shí),以第二種方法為準(zhǔn)。

Activity中Intent與IntentFilter的匹配規(guī)則:

在前面介紹Activity的激活方法時(shí),我們已經(jīng)介紹了如何去用Intent去啟動(dòng)一個(gè)Activity,但我們所講的啟動(dòng)Activity是有兩種辦法,前面說(shuō)的是顯式啟動(dòng),意即是可以清楚知道Activity下一個(gè)跳轉(zhuǎn)的Activity是什么。(從Intent的參數(shù)對(duì)象就可以看出)。而關(guān)于啟動(dòng)Activity的另一種辦法–隱式啟動(dòng),則更多的是一舉通過(guò)Intent與IntentFilter的匹配來(lái)實(shí)現(xiàn)的。下面就介紹一下Activity中Intent與IntentFilter的匹配規(guī)則。

1.IntentFilter如何設(shè)定

在AndroidManifest.xml文件中,找到< application>,在指定的< activity>標(biāo)簽內(nèi)添加,如例:

 <activity
     android:name=".RegisterActivity"
     android:label="@string/app_name" >
     <intent-filter>
     <action android:name="android.intent.action.MAIN" />

     <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

 </activity>

2.Intent與IntentFilter的聯(lián)合工作

Intent與IntentFilter的聯(lián)合工作表現(xiàn)為:開(kāi)發(fā)者在需要啟動(dòng)一個(gè)Activity時(shí),通過(guò)Intent向傳遞每個(gè)Activity的IntentFilter發(fā)送一則消息,如果有某個(gè)Activity的預(yù)定義信息和接收到的Activity相匹配,則表示下一個(gè)要啟動(dòng)的Activity為該Activity。因?yàn)槲覀冊(cè)陂_(kāi)發(fā)者中并不能直接透過(guò)代碼看到下一個(gè)Activity是什么,只是透過(guò)這種信息匹配的方法去完成的Activity啟動(dòng)過(guò)程,就是隱式啟動(dòng)。

3.IntentFilter的過(guò)濾信息:

IntentFilter的過(guò)濾信息主要包括三種:action、category、data,三種過(guò)濾信息都有相應(yīng)的功能。如果一個(gè)Intent傳遞的信息同時(shí)匹配了IntentFilter設(shè)定的過(guò)濾信息,那么才能成功啟動(dòng)目標(biāo)Activity,否則就算失敗。不過(guò)注意的是,一個(gè)Activity可以設(shè)定多個(gè)IntentFilter,只要有其中一組IntentFilter完全匹配,同樣可以開(kāi)啟該Activity。
下面分別介紹三種過(guò)濾信息的作用:

action的匹配規(guī)則

action的本質(zhì)是一個(gè)字符串,其作用是描述Intent所觸發(fā)的動(dòng)作的名稱,我們知道,一個(gè)人可以有多種稱呼,當(dāng)其他人要找這個(gè)人時(shí),只需要叫他其中一個(gè)名字就可以了。同樣,在IntentFilter中,我們可以定義多個(gè)action,只要有一個(gè)action和Intent傳遞的信息匹配,那么就算配合成功。注意的是,系統(tǒng)本身預(yù)定義了一些action,代表可啟動(dòng)的一些預(yù)定義的Activity,比如撥號(hào)界面等這些預(yù)定義的action集中放在android.intent.action下,調(diào)用的時(shí)候從里面選取,比如:

android.intent.action.SEND

action在IntentFilter中的定義格式如下:

//actionName表示你需要加入的action信息
<action android:name="actionName"/>

action在Intent中的調(diào)用格式如下:

String action="actionName";
Intent intent =new Intent(action);

category匹配規(guī)則

category和action的本質(zhì)是一致的,但代表的意義不同,category描述的是目標(biāo)組件的類別信息,表明這個(gè)目標(biāo)可以干些什么,比如系統(tǒng)預(yù)定義中的:

CATEGORY_GADGET:表示目標(biāo)Activity是可以嵌入到其他Activity中的

當(dāng)然,我們也可以給它進(jìn)行自定義的設(shè)置。
而關(guān)于category的匹配規(guī)則,大致如下:如果Intent中含有category,那么不管你有幾個(gè),都需要和目標(biāo)Activity在IntentFilter中設(shè)定的category匹配。哪怕有一個(gè)是不匹配的,都將報(bào)下面這個(gè)異常:

android.content.ActivityNotFoundException:No Activity found to handle Intent {act=actionName cat=[categoryName]}

category在IntentFilter中的定義格式如下:

<category android:name="android.intent.category.LAUNCHER" />

category在Intent中的添加category調(diào)用格式如下:

String category ="categoryName";
intent.addCategory(category);

data匹配規(guī)則

data的匹配規(guī)則和action相似,如果IntentFilter中定義了data,那么Intent中必須也要定義可匹配的data,但是因?yàn)閐ata的結(jié)構(gòu)與action不一樣,所以會(huì)有一些變化的地方。

data的組成

data由兩部分組成:mimeType 和URI。其中,mimeType指的媒體類型,可以表示圖片image/jpeg,文本text/html ,音頻audio/mpeg4-generic 和視頻video/*等。而URI表示統(tǒng)一資源標(biāo)識(shí)符(Uniform Resource Identifier),用以制定所需資源的存儲(chǔ)路徑。其結(jié)構(gòu)如下:

<scheme>://<host>:<port>:/[<path>|<pathPrefix>|<pathfrefix>]

結(jié)構(gòu)說(shuō)明如下:
scheme:URI的模式,比如http、file等
host:URI的主機(jī)名,即當(dāng)前資源所在的主機(jī)的IP地址,可以用域名表示,如www.baidu.com
port:URI的端口號(hào),比如80,指獲得資源的窗口路徑。
path、pathPrefix、pathPattern:表示路徑信息

data在IntentFilter的定義格式:

<data 
   android:mimeType="mimeName"
   android:scheme="schemeName"
   android:host="hostName"
   android:port="portName"
   android:path="pathName"
   android:pathPrefix="pathPrefixName"
   android:pathPattern="pathPatternName"
/>

或者:

<data android:mimeType="mimeName"/>
<data android:scheme="schemeName"/>
......
<data android:pathPattern="pathPatternName"/>

data在Intent中的調(diào)用方法有:

intent.setdata(Uri data);
intent.setDataAndNormalize(Uri data);
intent.setDataAndType(Uri data, String type);
intent.setDataAndType(Uri data, String type);
intent.setDataAndTypeAndNormalize(Uri data, String type);

總結(jié)

以上就是本文關(guān)于Activity生命周期與啟動(dòng)模式圖文解說(shuō)的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

最新評(píng)論