(四)Activity與Activity調(diào)用棧

本文為Android的Activity相關(guān)知識整理,具體參考了

  • 《Android開發(fā)藝術(shù)探索》第一章
  • 《Android群英傳》第八章
  • 《第一行代碼》第二章

Activity是與用戶交互的第一接口。

  1. Activity生命周期

Activity具有多種形態(tài)。其生命周期圖如下:


Paste_Image.png

其中,有三個穩(wěn)定態(tài)予弧,其他都是過渡態(tài):

  • Resumed 薛匪,此時打瘪,Activity處于棧頂历筝,處理用戶交互酗昼。
  • Paused,當(dāng)Activity的一部分被擋住的時候進入這個狀態(tài)梳猪,不會與用戶交互麻削。
  • Stopped,當(dāng)Activity完全被覆蓋時進入這個狀態(tài)春弥,此時Activity不可見呛哟,僅在后臺運行。

1.1 Activity經(jīng)典生命周期

(以下均指MainActivity的生命周期)

  • Activity啟動匿沛,點開一個應(yīng)用展示MainActivity
    • onCreate()->onStart()->onResume() 到達(dá)Resumed狀態(tài)竖共,此時MainActivity被打開。
  • Activity暫停與恢復(fù)俺祠,1:打開了一個半屏幕的dialog公给,2:按返回鍵返回MainActivity
    1. onPause()到達(dá)Paused狀態(tài),此時dialog被打開蜘渣。
    2. onResume()到達(dá)Resumed狀態(tài)淌铐,此時dialog被關(guān)閉,顯示MainActivity
  • Activity停止與恢復(fù)蔫缸,1:打開另一個SecondActivity腿准,2:按返回鍵返回MainActivity
    1. onPause()->onStop()到Stopped狀態(tài),此時SecondActivity被打開拾碌。
    2. onRestart()->onStart()->onResume()到Resumed狀態(tài)吐葱,此時SecondActivity被關(guān)閉,重新回到MainActivity校翔。
  • Activity銷毀弟跑,在MainActivity按返回鍵
  • onPause()->onStop()->onDestory(),此時已經(jīng)銷毀 MainActivity防症。

注意:

  • 在onPause()中一定要釋放使用的系統(tǒng)資源孟辑,比如Camera,sensor蔫敲,receiversK撬浴!
  • 在onStop()中執(zhí)行更大奈嘿、更多CPU密集的關(guān)閉操作貌虾。比如寫入信息到數(shù)據(jù)庫。
  • 當(dāng)系統(tǒng)長期處于onStopped狀態(tài)而且此時系統(tǒng)內(nèi)存緊張時裙犹,系統(tǒng)會回收此Activity尽狠,而此時衔憨,系統(tǒng)會通過onSaveInstanceState()方法將Activity狀態(tài)保存到Bundle對象中(finish()方法銷毀時不會保存)。當(dāng)重新創(chuàng)建此Activity時晚唇,保存的Bundle對象會傳遞到onRestoreInstanceState()與onCreate()中巫财。
  • onCreate和onDestroy是配對的,分別標(biāo)識著Activity的創(chuàng)建和銷毀; onStart和onStop是配對的哩陕,標(biāo)識著Activity是否可見;onResume和onPause是配對的平项,標(biāo)識著Activity是否在前臺
  • 假設(shè)當(dāng)前Activity為MainAcitivty 悍及,這時用戶啟動SecondActivity 闽瓢,那么MainAcitivty 的onPause先執(zhí)行,SecondActivity 的onResume后執(zhí)行心赶。Android規(guī)定扣讼,不能在onPause中做重量級操作,就是基于這里缨叫。我們應(yīng)該盡量在onStop中做操作椭符,使得新Activity盡快顯示
  • MainAcitivty->onPause
  • SecondActivity->onCreate
  • SecondActivity->onStart
  • SecondActivity->onResume
  • MainAcitivty->onStop

1.2 異常生命周期

以下幾種情況下,Activity的生命周期會發(fā)生異常
1耻姥,資源相關(guān)的系統(tǒng)配置發(fā)生改變
比如销钝,旋轉(zhuǎn)屏幕,在默認(rèn)狀態(tài)下琐簇,Activity就會被銷毀并且重新創(chuàng)建蒸健。

  • 首先,Activity就會被銷毀婉商,onPause(), onStop(),onDestory()均會被調(diào)用似忧,同時由于Activity是在異常狀態(tài)下終止的,系統(tǒng)會在onStop()之前丈秩,調(diào)用onSaveInstanceState()來保存當(dāng)前Activity的狀態(tài)盯捌。
  • 然后,Activity被重新創(chuàng)建癣籽,系統(tǒng)會在onStart()之后挽唉,調(diào)用onRestoreInstanceState(),并且把之前保存的Bundle對象傳遞給onRestoreInstanceState()和onCreate()方法筷狼。
  • PS: 這兩個方法都能對Bundle數(shù)據(jù)進行處理,但是一般用 onRestoreInstanceState()匠童。因為onRestoreInstanceState()一旦被調(diào)用埂材,其參數(shù) Bundle savedInstanceState 一定是有值的,我們不必判斷其是否為空汤求。
@Override
protected void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  if(savedInstanceState != null){
       String test = savedInstanceState.getString("extre_test");
       Log.d(TAG, test);
   }
 }

@Override
protected void onSaveInstanceState(Bundle outState){
  super.onSaveInstanceState(outState);
  outState.putString("extre_test", "test");
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
  super.onRestoreInstanceState(savedInstanceState);
  String test = savedInstanceState.getString("extre_test");
  Log.d(TAG, test);
}

執(zhí)行順序:
1 onPause()
2 onSaveInstanceState(Bundle outState)
3 onStop()
4 onDestory()
5 onCreate(Bundle savedInstanceState)
6 onStart()
7 onRestoreInstanceState(Bundle savedInstanceState)

注意:系統(tǒng)僅僅在Activity異常終止時才會調(diào)用onRestoreInstanceState()俏险。

2严拒,系統(tǒng)內(nèi)存不足
此時的系統(tǒng)中數(shù)據(jù)的存儲和恢復(fù)情況和上面第一種情況一致。Activity優(yōu)先級如下:

1 前臺Activity
2 可見但非前臺Activity
3 后臺Activity
當(dāng)系統(tǒng)資源不足的時候竖独,會按照這個優(yōu)先級使用onSaveInstanceState()和onRestoreInstanceState()來存儲和恢復(fù)數(shù)據(jù)裤唠。

還有一些后臺進程不是四大組件,這樣就會很容易被殺死~~ 一般是將這些后臺工作放入Service中莹痢,從而保證有一定的優(yōu)先級种蘸。

PS:阻止Activity被重新創(chuàng)建

使用android:configChanges="orientation|screenSize"屬性。

常用屬性:

  • locale:設(shè)備的本地位置發(fā)生變化竞膳,一般指切換了系統(tǒng)語言航瞭。
  • orientation:屏幕方向發(fā)生變化
  • screenSize:屏幕大小發(fā)生變化,當(dāng)旋轉(zhuǎn)屏幕的時候坦辟,屏幕尺寸會變?睢!o弊摺滨彻!這個比較特殊,當(dāng)minSdkVersion和targetSdkVersion均低于13時挪蹭,此選項不會導(dǎo)致Activity重啟亭饵,否則會導(dǎo)致Activity重啟。
  • keyboardHidden:鍵盤的可訪問性發(fā)生變化嚣潜,比如調(diào)出鍵盤冬骚。
 <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:configChanges="orientation|screenSize|keyboardHidden" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

@Override
public void onConfigurationChanged(Configuration newConfig){
    super.onConfigurationChanged(newConfig);
    ......//當(dāng)系統(tǒng)配置發(fā)上變換時,進行的工作
}
  1. Android任務(wù)棧

Android的APP通常會有多個Activity懂算,各個Activity之間通過Intent進行連接只冻,系統(tǒng)通過棧結(jié)構(gòu)來保存整個APP的Activity。系統(tǒng)有兩種方式控制Activity的啟動模式计技。

  • AndroidMainifest的launchMode
  • Intent Flag(優(yōu)先級更高)

2.1AndroidMainifest啟動模式

在AndroidMainifest.xml文件里面的activity標(biāo)簽設(shè)置啟動模式喜德。

<activity
    android:name=".FirstActivity"
    android:launchMode="singleTop"
    android:label="This is FirstActivity" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
  • standard,標(biāo)準(zhǔn)模式垮媒,每次都會創(chuàng)建新的Activity覆蓋在原Activity上
    Paste_Image.png
  • singleTop舍悯,棧頂復(fù)用模式,首先判斷棧頂Activity是否是要啟動的Activity睡雇,如果是則不創(chuàng)建新的Activity而直接引用這個Activity萌衬;如果不是則創(chuàng)建新的Activity。
Paste_Image.png
  • singleTask它抱,棧內(nèi)復(fù)用模式秕豫,檢測整個Activity棧中是否存在當(dāng)前需要啟動的Activity,如果存在則將該Activity置于棧頂,并銷毀其上所有Activity混移。
Paste_Image.png
  • singleInstance祠墅,單實例模式,創(chuàng)建新的任務(wù)棧歌径,且該任務(wù)棧僅有一個Activity毁嗦。
Paste_Image.png

TaskAffinity
taskAffinity速挑,任務(wù)相關(guān)性晨抡。xml中的一個屬性,標(biāo)識了一個Activity所需要的任務(wù)棧的名字失驶。默認(rèn)是包名勺届。如果設(shè)置了其他的名字如com.test.task1驶俊,那啟動它的時候就會新建一個名為com.test.task1的任務(wù)棧。

 <activity
    android:name="com.test.task0.MainActivity"
    android:label="@string/app_name"
    android:launchMode="standard">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category andorid:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity
    andorid:name="com.test.SecondActivity"
    android:taskAffinity="com.test.task1"
    android:label="@string/app_name"
    android:launchMode="singleTask"/>

<activity
    andorid:name="com.test.ThirdActivity"
    android:taskAffinity="com.test.task1"
    android:label="@string/app_name"
    android:launchMode="singleTask"/>

如果從MainActivity啟動SecondActivity免姿,然后再啟動ThirdActivity饼酿,那么任務(wù)棧如下:
com.test.task0 MainActivity
com.test.task1 SecondActivity ThirdActivity
若再從ThirdActivity啟動MainActivity,那么任務(wù)棧如下:
com.test.task0 MainActivity
com.test.task1 SecondActivity ThirdActivity MainActivity

2.2 Intent Flag啟動模式

對Intent進行設(shè)置

 Intent intent = new Intent();
 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  

重要的Flag:

  • FLAG_ACTIVITY_NEW_TASK胚膊,啟動的Activity在新的Task中故俐,相當(dāng)于android:launchMode="newTask"
  • FLAG_ACTIVITY_SINGLE_TOP,相當(dāng)于android:launchMode="singleTop"
  • FLAG_ACTIVITY_CLEAR_TOP紊婉,相當(dāng)于android:launchMode="singleTask"
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS药版,當(dāng)以此種模式啟動A,A再啟動B時喻犁,A會被銷毀槽片。等同于android:excludeFromeRecents="true"

3 IntentFilter的匹配規(guī)則

  <activity android:name="SecondActivity">
      <intent-filter>
          <action android:name="android.intent.action.SEND">
          <category android:name="android.intent.category.DEFAULT">
          <data android:mimeType="text/plain">
      </intent-filter>
    </activity>

調(diào)用一個Activity主要包括兩種:
1,顯式調(diào)用肢础。

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

2, 隱式調(diào)用

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setDataAndType(Uri.parse("file://abc"), "text/plain"); 
startActivity(intent);

隱式調(diào)用需要Intent能夠匹配目標(biāo)組件的IntentFilter中的過濾信息还栓。
IntentFilter中的過濾信息有action, category, data。
只有一個Intent同時匹配這三個類別才能啟動目標(biāo)Activity传轰。

  • action的匹配要求剩盒,Intent中的action存在且必須和過濾規(guī)則中的其中一個action相同。
  • data的匹配要求慨蛙,Intent中的data存在且必須和過濾規(guī)則中的其中一個data相同辽聊。
  • category匹配要求,如果含有category期贫,那么所有的category都必須和過濾規(guī)則中的其中一個category相同跟匆。也就是說它的category可以沒有!M场<致痢!2号痢(原因是默認(rèn)的category是android.intent.category.DEFAULT垢揩,不過得在activity標(biāo)簽的intent-filter中加入android.intent.category.DEFAULT這個category)
  1. 退出程序的兩種方法

4.1 利用Activity的singleTask模式退出

  1. 將主Activity設(shè)置為singleTask模式

    •  <activity
           android:name=".MainActivity"
           android:launchMode="singleTask"
           ...
      
  • 在要退出的Activity中轉(zhuǎn)到主Activity中,從而將主Activity之上的Activity都清除
    • Intent intent = new Intent(this, MainActivity.class);
      startActivity(intent); 
      
  • 然后重寫主Activity的onNewIntent()方法敛瓷,在方法中加上finish()叁巨,從而銷毀最后一個Activity。
    • @Override
      protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            finish();
      }
      

4.2 利用專門的集合類對所有的活動進行管理

  1. 創(chuàng)建一個ActivityCollector 類作為活動管理器呐籽。List<Activity>作為存放活動的列表锋勺。

    • public class ActivityCollector {
        public static List<Activity> activities = new ArrayList<Activity>();
        public static void addActivity(Activity activity) {
          activities.add(activity);
        }
      
        public static void removeActivity(Activity activity) {
            activities.remove(activity);
        }
      
        public static void finishAll() {
            for (Activity activity : activities) {
                if (!activity.isFinishing()) {
                    activity.finish();
                }
            }
        }
      }
      
  2. 創(chuàng)建一個繼承自Activity的BaseActivity 。ActivityCollector里存放的活動要隨著onCreate而添加狡蝶,隨著onDestory而銷毀庶橱。

    • public class BaseActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d("BaseActivity", getClass().getSimpleName());
            ActivityCollector.addActivity(this);
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
      }
      
  3. 全部的Activity都要繼承自BaseActivity,此時贪惹,只要調(diào)用 ActivityCollector.finishAll();苏章,就可以銷毀所有Activity,關(guān)掉程序奏瞬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枫绅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子硼端,更是在濱河造成了極大的恐慌并淋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件珍昨,死亡現(xiàn)場離奇詭異县耽,居然都是意外死亡,警方通過查閱死者的電腦和手機镣典,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門兔毙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骆撇,你說我怎么就攤上這事瞒御。” “怎么了神郊?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵肴裙,是天一觀的道長。 經(jīng)常有香客問我涌乳,道長蜻懦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任夕晓,我火速辦了婚禮宛乃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己征炼,他們只是感情好析既,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谆奥,像睡著了一般眼坏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酸些,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天宰译,我揣著相機與錄音,去河邊找鬼魄懂。 笑死沿侈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的市栗。 我是一名探鬼主播缀拭,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肃廓!你這毒婦竟也來了智厌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盲赊,失蹤者是張志新(化名)和其女友劉穎铣鹏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哀蘑,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡诚卸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绘迁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合溺。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缀台,靈堂內(nèi)的尸體忽然破棺而出棠赛,到底是詐尸還是另有隱情,我是刑警寧澤膛腐,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布睛约,位于F島的核電站,受9級特大地震影響哲身,放射性物質(zhì)發(fā)生泄漏辩涝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一勘天、第九天 我趴在偏房一處隱蔽的房頂上張望怔揩。 院中可真熱鬧捉邢,春花似錦、人聲如沸商膊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翘狱。三九已至秘案,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間潦匈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工赚导, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茬缩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓吼旧,卻偏偏與公主長得像凰锡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子圈暗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 【 Android四大組件之一 主要用于與用戶進行交互掂为,在一個App中可能存在零個或多個Activity 】 1....
    征程_Journey閱讀 1,952評論 0 4
  • Activity 一、四種形態(tài) 運行狀態(tài): 當(dāng) Activity 處于棧的頂層员串,可見勇哗,并可與用戶進行交互 onRe...
    任教主來也閱讀 1,657評論 1 10
  • 今年中秋,月兒主角失約了寸齐。 她只管躲在月宮欲诺,清輝滿人間便成了人們的奢想。倒是涼涼秋雨殷勤得很渺鹦,一連兩三天纏綿于人間...
    滋小然閱讀 819評論 35 27
  • 文/ Kurny 這是古老得不能再古老的列車 它長長的長著犄角的頭部 不知何時起扰法,已沒有了生氣 零零散散布了些紅銹...
    Kurny91閱讀 328評論 2 0
  • “彼岸花” 黃泉彼岸 生生相惜 世世相錯 “三生石 ” 忘川三生石 望不穿三生 三生石上卻早已一定 “奈何橋” 奈...
    大志志大xcz閱讀 270評論 0 0