Android Activity 生命周期詳解及監(jiān)聽(tīng)

前言

Activity/Fragment/View 系列文章:

Android Activity 與View 的互動(dòng)思考
Android Activity 生命周期詳解及監(jiān)聽(tīng)
Android onSaveInstanceState/onRestoreInstanceState 原來(lái)要這么理解
Android Fragment 要你何用?
Android Activity/View/Window/Dialog/Fragment 深層次關(guān)聯(lián)(白話解析)

當(dāng)你編寫第一個(gè)Android "Hello World" 時(shí)坤按,已經(jīng)不知不覺(jué)地與Activity生命周期打交道待牵。這部分是是Android 最基礎(chǔ)的知識(shí)之一,也是面試的持づ福客,同時(shí)也是理解Jetpack 組件的基礎(chǔ)勤晚。
網(wǎng)上關(guān)于此的文章數(shù)不勝數(shù)枉层,但大部分只流于表象,沒(méi)有系統(tǒng)性分析赐写,看過(guò)之后容易忘卻鸟蜡。本系列將會(huì)著重分析由此衍生的一系列知識(shí)點(diǎn)。
通過(guò)本篇文章挺邀,你將了解到:

1揉忘、什么是生命周期?
2端铛、誰(shuí)是生命周期的幕后黑手泣矛?
3、如何感知生命周期

1禾蚕、什么是生命周期

這個(gè)名字并不是計(jì)算機(jī)獨(dú)創(chuàng)的術(shù)語(yǔ)您朽,任何有生命的東西都有周期,從出生到死亡换淆,以人為例:


image.png

這是一個(gè)人的成長(zhǎng)軌跡哗总,也是一個(gè)人的生命周期几颜,在不同的年齡段表現(xiàn)各異。
俗話說(shuō):人活一世讯屈,草木一秋蛋哭。
佛家說(shuō)的輪回,當(dāng)一個(gè)人入土為安涮母,假設(shè)有輪回具壮,在下一個(gè)輪回里再經(jīng)歷出生到死亡,這個(gè)人還是上一世的那個(gè)人嗎哈蝇?
同樣的草木凋謝了棺妓,在春天再長(zhǎng)出來(lái)時(shí),還是曾經(jīng)的它嗎炮赦?
不是怜跑,它們都是新的生命。

Activity 的生命周期

先來(lái)看官方經(jīng)典圖:


image.png

Activity 作為對(duì)象吠勘,它是有"生命的"性芬,類似人和草木,它的存活周期就是它的生命周期剧防。

為什么生命周期要分不同的階段植锉?
就像人一樣:

1、當(dāng)處在嬰兒階段峭拘,自己每天喝喝奶俊庇,沒(méi)事就哭鬧一下,大人就會(huì)安撫你鸡挠。
2辉饱、當(dāng)處在學(xué)生時(shí)代,就認(rèn)真做題拣展,大家把你當(dāng)小孩看待彭沼,不用你出門賺錢,景點(diǎn)都能給你學(xué)生票五折優(yōu)惠备埃。
3姓惑、當(dāng)處在工作時(shí)代,就好好搬磚按脚,老板會(huì)給你福報(bào)于毙。
4、...

同樣的乘寒,對(duì)于Activity 來(lái)說(shuō)望众,在不同的階段自己內(nèi)部所做的事情不同匪补,外部監(jiān)聽(tīng)到Activity的處在不同階段將會(huì)采取不同的措施伞辛。
總結(jié)來(lái)說(shuō):

生命周期分階段既是為了"生命體內(nèi)部"流轉(zhuǎn)的需要烂翰,也是為了讓外部知道"生命體"當(dāng)前所處的階段進(jìn)而做出相應(yīng)的決策。

與人蚤氏、草木一樣甘耿,當(dāng)Activity 經(jīng)歷了一個(gè)生命周期后,再次重建時(shí)已經(jīng)不是當(dāng)初的對(duì)象了竿滨。

Activity 生命周期不同階段

主要分為:


image.png

可以看出Create 對(duì)應(yīng) Destroy佳恬,Start對(duì)應(yīng)Stop,Resume對(duì)應(yīng)Pause于游。
既然每個(gè)階段都有回調(diào)毁葱,那么只需要重寫對(duì)應(yīng)的回調(diào)方法,添加打印即可測(cè)試不同的操作后Activity處在哪個(gè)階段贰剥。

接下來(lái)看看Activity 常見(jiàn)的切換場(chǎng)景:

Activity A 啟動(dòng)Activity B

image.png

圖上數(shù)字表示發(fā)生的順序倾剿,具有時(shí)間上的先后順序。

從Activity A 按Home回到桌面

回到桌面或者最近任務(wù)列表:


image.png

Activity B 按back 鍵/調(diào)用finish

此時(shí)Activity B處在棧頂位置蚌成,而Activity A 位于它之下前痘。


image.png

Pause 階段

上面列出的場(chǎng)景都是onPause-->onStop,那么Activity 是否存在只停留在onPause的階段担忧?
Pause階段是Activity 可見(jiàn)芹缔,但是沒(méi)有焦點(diǎn)因此無(wú)法和用戶交互。
可見(jiàn)意味著它的上面有Activity瓶盛,并且上面的Activity 是透明的最欠,才可以看見(jiàn)底下的Activity。
此種情況下惩猫,底下的Activity 處在Pause階段窒所。


tt0.top-918926.gif

如上圖,紅色區(qū)塊是新啟動(dòng)的Activity帆锋,該Activity 沒(méi)有全屏并且透明吵取,可以看到底下Activity 內(nèi)容,此時(shí)它處在Pause階段锯厢。

2皮官、誰(shuí)是生命周期的幕后黑手?

我們知道Android 是事件驅(qū)動(dòng)的实辑,通過(guò)Loop來(lái)循環(huán)執(zhí)行MessageQueue里的Message捺氢。
問(wèn)題來(lái)了:onCreate、onStart剪撬、onStop 是在同一個(gè)Message里執(zhí)行的嗎摄乒?
要弄清楚這個(gè)問(wèn)題,需要知道回調(diào)這些方法的堆棧。眾所周知馍佑,四大組件都是由AMS(Activity Manager Service)控制的斋否,而AMS 運(yùn)行在system_server 進(jìn)程,與咱們的App是不同的進(jìn)程拭荤,AMS 通過(guò)Binder 與各個(gè)App進(jìn)行通信茵臭。

image.png

不清楚的可移步:Android 四大組件通信核心
接下來(lái)探究AMS 如何控制Activity 生命周期回調(diào)的。

onCreate 調(diào)用堆棧

在onCreate()里打個(gè)斷點(diǎn)舅世,調(diào)用棧如下:


image.png

可以看出入口是在ActivityThread.java 類里旦委。


image.png

1、App進(jìn)程啟動(dòng)的時(shí)雏亚,將ApplicationThread 傳遞給AMS缨硝,類似向AMS 注冊(cè)回調(diào)。
2罢低、AMS 通過(guò)ApplicationThread 通知App Activity 的生命周期追葡。
3、App 切換到主線程執(zhí)行對(duì)應(yīng)的方法奕短,最終會(huì)執(zhí)行Activity 的onCreate()宜肉、onStart()、onResume()等方法翎碑。

其它階段的調(diào)用棧

與onCreate 類似谬返,onStart、onResume日杈、onPause遣铝、onStop、onDestroy 階段同樣經(jīng)歷了AMS--->App--->切換到主線程--->回調(diào)對(duì)應(yīng)方法莉擒。
為方便起見(jiàn)酿炸,省去AMS 過(guò)程,用圖表示如下:


image.png
image.png
image.png

由以上分析可知:

1涨冀、Activity 生命周期的幕后黑手是AMS填硕。
2、各個(gè)階段的調(diào)用棧很相似鹿鳖,只是變了方法名而已扁眯。
3、onCreate翅帜、onStart姻檀、onStop 不是在同一個(gè)Message里執(zhí)行的,但是都是在主線程執(zhí)行涝滴。

3绣版、如何感知生命周期

注冊(cè)監(jiān)聽(tīng)

知道了生命周期的來(lái)龍去脈胶台,要監(jiān)聽(tīng)生命周期就變得非常簡(jiǎn)單了,只需要在Activity 里重寫對(duì)應(yīng)階段的回調(diào)方法即可杂抽,這也是我們最基礎(chǔ)的選擇诈唬。
現(xiàn)在有個(gè)需求:監(jiān)聽(tīng)App處在前臺(tái)還是后臺(tái)?
Activity 處在后臺(tái)默怨,那么此時(shí)階段為Stop讯榕,回到前臺(tái)那么此時(shí)處會(huì)經(jīng)歷Start階段骤素,在進(jìn)入Start 階段時(shí)記錄+1匙睹,在進(jìn)入Stop階段時(shí)記錄-1。若最終結(jié)果記錄=1济竹,說(shuō)明App在前臺(tái)痕檬。
這么看來(lái),我們需要一個(gè)公共的Activity來(lái)進(jìn)行統(tǒng)一記錄送浊,每個(gè)新建的Activity 都繼承自它梦谜,這么做雖然能滿足需求,但也有弊端:一是工作量大袭景,二是也不靈活唁桩。
實(shí)際上還有更好的方式來(lái)全局監(jiān)聽(tīng)各個(gè)Activity 生命周期。

#Application.java
    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.add(callback);
        }
    }

Application.java 里有個(gè)方法耸棒,顧名思義用來(lái)注冊(cè)Activity 生命周期回調(diào)的荒澡,這個(gè)callback 會(huì)加入到回調(diào)List:mActivityLifecycleCallbacks 里。
先看看ActivityLifecycleCallbacks 的構(gòu)成:


image.png

它是個(gè)接口与殃,乍一看有很多方法单山,實(shí)際上都是有規(guī)律可循的,總結(jié)下來(lái)就是監(jiān)聽(tīng)了:

Create幅疼、Start米奸、Resume、Pause爽篷、Stop悴晰、Destroy、SaveInstanceState

各個(gè)階段的回調(diào)逐工。
而每個(gè)階段分為三個(gè)小階段:

此階段之前膨疏、階段中、此階段之后

如對(duì)于Create階段钻弄,定義了三個(gè)回調(diào)方法:

#Application.java
    public interface ActivityLifecycleCallbacks {
        //Create階段之前
        default void onActivityPreCreated(@android.annotation.NonNull Activity activity,
                                          @android.annotation.Nullable Bundle savedInstanceState) {
        }

        //Create階段當(dāng)中
        void onActivityCreated(@android.annotation.NonNull Activity activity, @android.annotation.Nullable Bundle savedInstanceState);

        //Create階段之后
        default void onActivityPostCreated(@android.annotation.NonNull Activity activity,
                                           @android.annotation.Nullable Bundle savedInstanceState) {
        }
        //...
    }

而只有處在當(dāng)前階段的方法必須要實(shí)現(xiàn)類實(shí)現(xiàn)佃却,其它兩個(gè)方法都是默認(rèn)的(default 修飾)。

生命周期回調(diào)原理

注冊(cè)了監(jiān)聽(tīng)后窘俺,來(lái)分析一下該回調(diào)是如何被調(diào)用的饲帅。
既然是監(jiān)聽(tīng)Activity 生命周期复凳,那么應(yīng)當(dāng)從Activity.java 里入手。
記得咱們之前分析的Activity 回調(diào)方法調(diào)用棧灶泵,還是以onCreate為例:

#Activity.java
    protected void onCreate(@android.annotation.Nullable Bundle savedInstanceState) {
        ...
        mFragments.dispatchCreate();
        //分發(fā)
        dispatchActivityCreated(savedInstanceState);
        ...
    }

    private void dispatchActivityCreated(@android.annotation.Nullable Bundle savedInstanceState) {
        //調(diào)用Application里的方法
        getApplication().dispatchActivityCreated(this, savedInstanceState);
    }

而在Application.java里的實(shí)現(xiàn)為:

#Application.java
    void dispatchActivityCreated(@android.annotation.NonNull Activity activity,
                                               @android.annotation.Nullable Bundle savedInstanceState) {
        //收集注冊(cè)列表育八,即是將mActivityLifecycleCallbacks(List),轉(zhuǎn)為數(shù)組
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                //調(diào)用對(duì)應(yīng)的回調(diào)方法
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
                        savedInstanceState);
            }
        }
    }

雖然以上只是分析了onCreate赦邻,然而其他方法也是同樣的套路髓棋,大同小異。

1惶洲、每當(dāng)Activity 處在不同的階段時(shí)按声,會(huì)檢測(cè)Application里是否有監(jiān)聽(tīng)它(Activity)的生命周期,若是則告知監(jiān)聽(tīng)者當(dāng)前所處的階段恬吕。
2签则、若是重寫了Activity 對(duì)應(yīng)的方法,并添加了打印铐料,那么Application里的回調(diào)方法先執(zhí)行才會(huì)執(zhí)行到Activity里的打印渐裂,因?yàn)樗窃贏ctivity父類里執(zhí)行的。

以上即是Activity 生命周期的梳理钠惩,下篇將會(huì)分析onSaveInstanceState/onRestoreInstanceState 原理以及應(yīng)用場(chǎng)景柒凉,并引入Jetpack ViewModel與之對(duì)比。

透明Activity/生命周期監(jiān)聽(tīng) demo 請(qǐng)查看:github合集

本文基于Android 10.0

您若喜歡篓跛,請(qǐng)點(diǎn)贊膝捞、關(guān)注,您的鼓勵(lì)是我前進(jìn)的動(dòng)力

持續(xù)更新中举塔,和我一起步步為營(yíng)系統(tǒng)绑警、深入學(xué)習(xí)Android

1、Android各種Context的前世今生
2央渣、Android DecorView 必知必會(huì)
3计盒、Window/WindowManager 不可不知之事
4、View Measure/Layout/Draw 真明白了
5芽丹、Android事件分發(fā)全套服務(wù)
6北启、Android invalidate/postInvalidate/requestLayout 徹底厘清
7、Android Window 如何確定大小/onMeasure()多次執(zhí)行原因
8拔第、Android事件驅(qū)動(dòng)Handler-Message-Looper解析
9咕村、Android 鍵盤一招搞定
10、Android 各種坐標(biāo)徹底明了
11蚊俺、Android Activity/Window/View 的background
12懈涛、Android Activity創(chuàng)建到View的顯示過(guò)
13、Android IPC 系列
14泳猬、Android 存儲(chǔ)系列
15批钠、Java 并發(fā)系列不再疑惑
16宇植、Java 線程池系列
17、Android Jetpack 前置基礎(chǔ)系列

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末埋心,一起剝皮案震驚了整個(gè)濱河市指郁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拷呆,老刑警劉巖闲坎,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異茬斧,居然都是意外死亡腰懂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門啥供,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悯恍,“玉大人库糠,你說(shuō)我怎么就攤上這事伙狐。” “怎么了瞬欧?”我有些...
    開(kāi)封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵贷屎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我艘虎,道長(zhǎng)唉侄,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任野建,我火速辦了婚禮属划,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘候生。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布语盈。 她就那樣靜靜地躺著搀缠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪目溉。 梳的紋絲不亂的頭發(fā)上明肮,一...
    開(kāi)封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音缭付,去河邊找鬼柿估。 笑死,一個(gè)胖子當(dāng)著我的面吹牛陷猫,可吹牛的內(nèi)容都是我干的秫舌。 我是一名探鬼主播只厘,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舅巷!你這毒婦竟也來(lái)了羔味?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钠右,失蹤者是張志新(化名)和其女友劉穎赋元,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體飒房,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搁凸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狠毯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片护糖。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嚼松,靈堂內(nèi)的尸體忽然破棺而出嫡良,到底是詐尸還是另有隱情,我是刑警寧澤献酗,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布寝受,位于F島的核電站,受9級(jí)特大地震影響罕偎,放射性物質(zhì)發(fā)生泄漏很澄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一颜及、第九天 我趴在偏房一處隱蔽的房頂上張望甩苛。 院中可真熱鬧,春花似錦俏站、人聲如沸讯蒲。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)爱葵。三九已至,卻和暖如春反浓,著一層夾襖步出監(jiān)牢的瞬間萌丈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工雷则, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辆雾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓月劈,卻偏偏與公主長(zhǎng)得像度迂,于是被迫代替她去往敵國(guó)和親藤乙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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