Activity全方位了解,總有你不知道的一面

關于Activity,是我們接觸Android時頻繁了解的東西。其生命周期,啟動模式等內容也耳熟能詳。今天將系統而全面的總結Activity中的內容。

一、Activity的生命周期

本節內容將生命周期的情況分為兩部分介紹,第一部分先了解典型的生命周期的7個部分及Activity的狀態。第二部分會介紹Activity在一些特殊情況下的生命周期的經歷過程。

1.典型的生命周期的了解

先上經典圖片。



關于這張圖片,我們可能在初學Android時就有接觸,今天我們繼續回顧一下。

在正常情況下,一個Activity從啟動到結束會以如下順序經歷整個生命周期:
onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()。包含了六個部分,還有一個onRestart()沒有調用,下面我們一一介紹這七部分內容。

(1) onCreate():當 Activity 第一次創建時會被調用。這是生命周期的第一個方法。在這個方法中,可以做一些初始化工作,比如調用setContentView去加載界面布局資源,初始化Activity所需的數據。當然也可借助onCreate()方法中的Bundle對象來回復異常情況下Activity結束時的狀態(后面會介紹)。

(2) onRestart():表示Activity正在重新啟動。一般情況下,當當前Activity從不可見重新變為可見狀態時,onRestart就會被調用。這種情形一般是用戶行為導致的,比如用戶按Home鍵切換到桌面或打開了另一個新的Activity,接著用戶又回到了這個Actvity。(關于這部分生命周期的歷經過程,后面會介紹。)

(3) onStart(): 表示Activity正在被啟動,即將開始,這時Activity已經出現了,但是還沒有出現在前臺,無法與用戶交互。這個時候可以理解為Activity已經顯示出來,但是我們還看不到。

(4) onResume():表示Activity已經可見了,并且出現在前臺并開始活動。需要和onStart()對比,onStart的時候Activity還在后臺,onResume的時候Activity才顯示到前臺。

(5) onPause():表示 Activity正在停止,仍可見,正常情況下,緊接著onStop就會被調用。在特殊情況下,如果這個時候快速地回到當前Activity,那么onResume就會被調用(極端情況)。onPause中不能進行耗時操作,會影響到新Activity的顯示。因為onPause必須執行完,新的Activity的onResume才會執行。

(6) onStop():表示Activity即將停止,不可見,位于后臺??梢宰錾晕⒅亓考壍幕厥展ぷ?,同樣不能太耗時。

(7) onDestory():表示Activity即將銷毀,這是Activity生命周期的最后一個回調,可以做一些回收工作和最終的資源回收。

在平常的開發中,我們經常用到的就是 onCreate()和onDestory(),做一些初始化和回收操作。

生命周期的幾種普通情況

①針對一個特定的Activity,第一次啟動,回調如下:onCreate()->onStart()->onResume()

②用戶打開新的Activiy的時候,上述Activity的回調如下:onPause()->onStop()

③再次回到原Activity時,回調如下:onRestart()->onStart()->onResume()

④按back鍵回退時,回調如下:onPause()->onStop()->onDestory()

⑤按Home鍵切換到桌面后又回到該Actitivy,回調如下:onPause()->onStop()->onRestart()->onStart()->onResume()

⑥調用finish()方法后,回調如下:onDestory()(以在onCreate()方法中調用為例,不同方法中回調不同,通常都是在onCreate()方法中調用)

2.特殊情況下的生命周期

上面是普通情況下Activity生命周期的一些流程,但是在一些特殊情況下,Activity的生命周期的經歷有些異常,下面就是兩種特殊情況。
①橫豎屏切換
在橫豎屏切換的過程中,會發生Activity被銷毀并重建的過程。

在了解這種情況下的生命周期時,首先應該了解這兩個回調:onSaveInstanceState和onRestoreInstanceState。

在Activity由于異常情況下終止時,系統會調用onSaveInstanceState來保存當前Activity的狀態。這個方法的調用是在onStop之前,它和onPause沒有既定的時序關系,該方法只在Activity被異常終止的情況下調用。當異常終止的Activity被重建以后,系統會調用onRestoreInstanceState,并且把Activity銷毀時onSaveInstanceState方法所保存的Bundle對象參數同時傳遞給onSaveInstanceState和onCreate方法。因此,可以通過onRestoreInstanceState方法來恢復Activity的狀態,該方法的調用時機是在onStart之后。其中onCreate和onRestoreInstanceState方法來恢復Activity的狀態的區別:onRestoreInstanceState回調則表明其中Bundle對象非空,不用加非空判斷。onCreate需要非空判斷。建議使用onRestoreInstanceState。


橫豎屏切換的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()

可以通過在AndroidManifest文件的Activity中指定如下屬性:

android:configChanges = "orientation| screenSize"

來避免橫豎屏切換時,Activity的銷毀和重建,而是回調了下面的方法:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

②資源內存不足導致優先級低的Activity被殺死
Activity優先級的劃分和下面的Activity的三種運行狀態是對應的。

(1) 前臺Activity——正在和用戶交互的Activity,優先級最高。

(2) 可見但非前臺Activity——比如Activity中彈出了一個對話框,導致Activity可見但是位于后臺無法和用戶交互。

(3) 后臺Activity——已經被暫停的Activity,比如執行了onStop,優先級最低。

當系統內存不足時,會按照上述優先級從低到高去殺死目標Activity所在的進程。我們在平常使用手機時,能經常感受到這一現象。這種情況下數組存儲和恢復過程和上述情況一致,生命周期情況也一樣。

3.Activity的三種運行狀態

①Resumed(活動狀態)

又叫Running狀態,這個Activity正在屏幕上顯示,并且有用戶焦點。這個很好理解,就是用戶正在操作的那個界面。

②Paused(暫停狀態)

這是一個比較不常見的狀態。這個Activity在屏幕上是可見的,但是并不是在屏幕最前端的那個Activity。比如有另一個非全屏或者透明的Activity是Resumed狀態,沒有完全遮蓋這個Activity。

③Stopped(停止狀態)

當Activity完全不可見時,此時Activity還在后臺運行,仍然在內存中保留Activity的狀態,并不是完全銷毀。這個也很好理解,當跳轉的另外一個界面,之前的界面還在后臺,按回退按鈕還會恢復原來的狀態,大部分軟件在打開的時候,直接按Home鍵,并不會關閉它,此時的Activity就是Stopped狀態。

二、Activity的啟動模式

1.啟動模式的類別

Android提供了四種Activity啟動方式:

標準模式(standard)
棧頂復用模式(singleTop)
棧內復用模式(singleTask)
單例模式(singleInstance)

2.啟動模式的結構——棧

Activity的管理是采用任務棧的形式,任務棧采用“后進先出”的棧結構。


3.Activity的LaunchMode

(1)標準模式(standard)

每啟動一次Activity,就會創建一個新的Activity實例并置于棧頂。誰啟動了這個Activity,那么這個Activity就運行在啟動它的那個Activity所在的棧中。

例如:Activity A啟動了Activity B,則就會在A所在的棧頂壓入一個新的Activity。


特殊情況,如果在Service或Application中啟動一個Activity,其并沒有所謂的任務棧,可以使用標記位Flag來解決。解決辦法:為待啟動的Activity指定FLAG_ACTIVITY_NEW_TASK標記位,創建一個新棧。

應用場景:絕大多數Activity。如果以這種方式啟動的Activity被跨進程調用,在5.0之前新啟動的Activity實例會放入發送Intent的Task的棧的頂部,盡管它們屬于不同的程序,這似乎有點費解看起來也不是那么合理,所以在5.0之后,上述情景會創建一個新的Task,新啟動的Activity就會放入剛創建的Task中,這樣就合理的多了。

(2)棧頂復用模式(singleTop)

如果需要新建的Activity位于任務棧棧頂,那么此Activity的實例就不會重建,而是重用棧頂的實例。并回調如下方法:

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
    }

由于不會重建一個Activity實例,則不會回調其他生命周期方法。
如果棧頂不是新建的Activity,就會創建該Activity新的實例,并放入棧頂。


應用場景:在通知欄點擊收到的通知,然后需要啟動一個Activity,這個Activity就可以用singleTop,否則每次點擊都會新建一個Activity。當然實際的開發過程中,測試妹紙沒準給你提過這樣的bug:某個場景下連續快速點擊,啟動了兩個Activity。如果這個時候待啟動的Activity使用 singleTop模式也是可以避免這個Bug的。同standard模式,如果是外部程序啟動singleTop的Activity,在Android 5.0之前新創建的Activity會位于調用者的Task中,5.0及以后會放入新的Task中。

(3)棧內復用模式(singleTask)

該模式是一種單例模式,即一個棧內只有一個該Activity實例。該模式,可以通過在AndroidManifest文件的Activity中指定該Activity需要加載到那個棧中,即singleTask的Activity可以指定想要加載的目標棧。singleTask和taskAffinity配合使用,指定開啟的Activity加入到哪個棧中。

 <activity android:name=".Activity1"
             android:launchMode="singleTask"
             android:taskAffinity="com.lvr.task"
             android:label="@string/app_name">
      </activity>

關于taskAffinity的值:每個Activity都有taskAffinity屬性,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity,那么它的這個屬性就等于Application指明的taskAffinity,如果Application也沒有指明,那么該taskAffinity的值就等于包名。
執行邏輯:
在這種模式下,如果Activity指定的棧不存在,則創建一個棧,并把創建的Activity壓入棧內。如果Activity指定的棧存在,如果其中沒有該Activity實例,則會創建Activity并壓入棧頂,如果其中有該Activity實例,則把該Activity實例之上的Activity殺死清除出棧,重用并讓該Activity實例處在棧頂,然后調用onNewIntent()方法。

對應如下三種情況:



應用場景:大多數App的主頁。對于大部分應用,當我們在主界面點擊回退按鈕的時候都是退出應用,那么當我們第一次進入主界面之后,主界面位于棧底,以后不管我們打開了多少個Activity,只要我們再次回到主界面,都應該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂,而不是往棧頂新加一個主界面Activity的實例,通過這種方式能夠保證退出應用時所有的Activity都能報銷毀。在跨應用Intent傳遞時,如果系統中不存在singleTask Activity的實例,那么將創建一個新的Task,然后創建SingleTask Activity的實例,將其放入新的Task中。

(4)單例模式(singleInstance)

作為棧內復用模式(singleTask)的加強版,打開該Activity時,直接創建一個新的任務棧,并創建該Activity實例放入新棧中。一旦該模式的Activity實例已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的實例。


應用場景:呼叫來電界面。這種模式的使用情況比較罕見,在Launcher中可能使用?;蛘吣愦_定你需要使Activity只有一個實例。建議謹慎使用。

3.特殊情況——前臺棧和后臺棧的交互

假如目前有兩個任務棧。前臺任務棧為AB,后臺任務棧為CD,這里假設CD的啟動模式均為singleTask,現在請求啟動D,那么這個后臺的任務棧都會被切換到前臺,這個時候整個后退列表就變成了ABCD。當用戶按back返回時,列表中的activity會一一出棧,如下圖。


如果不是請求啟動D而是啟動C,那么情況又不一樣,如下圖。

調用SingleTask模式的后臺任務棧中的Activity,會把整個棧的Actvity壓入當前棧的棧頂。singleTask會具有clearTop特性,把之上的棧內Activity清除。

4.Activity的Flags

Activity的Flags很多,這里介紹集中常用的,用于設定Activity的啟動模式??梢栽趩覣ctivity時,通過Intent的addFlags()方法設置。

**(1)FLAG_ACTIVITY_NEW_TASK **
其效果與指定Activity為singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致。

(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位于它上面的Activity都要出棧。如果和singleTask模式一起出現,若被啟動的Activity已經存在棧中,則清除其之上的Activity,并調用該Activity的onNewIntent方法。如果被啟動的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧,然后創建新的Activity實例并壓入棧中。

以上就是本篇文章的內容。本篇文章的棧操作的圖片來自于xybCoder,特別感謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容