Android 重學(xué)系列 Activity生命周期的總結(jié)

前言

這是之前欠下的Activity 啟動(dòng)到銷毀的系列文章的總結(jié)即碗。Activity是四大組件中最為復(fù)雜的一環(huán)酵紫,就算是我也沒辦法說我全面的理解了籽腕,因此還是有必要把如下三篇文章,做一次小的總結(jié)惠啄。

這三篇分別論述了Activity在啟動(dòng)中,做的三個(gè)大事情:

  • Activity 啟動(dòng)準(zhǔn)備任内, 準(zhǔn)備好ActivityRecord對(duì)象
  • Activity 棧的轉(zhuǎn)移與變化
  • AMS 如何通信到Activity中執(zhí)行Activity對(duì)應(yīng)的生命周期

如果遇到什么問題歡迎來到本文討論:http://www.reibang.com/p/5da5f2bc8657

正文

我們先上時(shí)序圖:


Android O Activity啟動(dòng)流程.png

注意:紅色線代表跨越Binder一次進(jìn)程撵渡。

Activity 啟動(dòng)準(zhǔn)備

在Activity的前期準(zhǔn)備中,做了如下事情:

  • 1.通過ActivityStackSupervisor調(diào)用resolveIntentInternal 從PMS中通過Intent篩選出符合目標(biāo)的Activity死嗦,如果符合多個(gè)則切換成另一個(gè)彈窗Activity的啟動(dòng)趋距,這個(gè)Activity包含了當(dāng)前多個(gè)符合Intent目標(biāo)的Activity信息 也就是ActivityInfo

  • 2.獲取重量級(jí)進(jìn)程,這種進(jìn)程只允許在一個(gè)Android系統(tǒng)內(nèi)只有一個(gè)越走,一旦需要開啟另一個(gè)重量級(jí)進(jìn)程的Activity棚品,就會(huì)彈出一個(gè)彈框的Activity替換代替當(dāng)前的Activity,不過在其中就有了選擇哪一個(gè)進(jìn)程Activity的選項(xiàng)

  • 3.Android 9.0比起低版本來說多做不少事情,在startActivityMayWait方法中廊敌,會(huì)進(jìn)一步調(diào)用startActivity真正執(zhí)行啟動(dòng)方法铜跑。根據(jù)執(zhí)行方法返回的狀態(tài)代碼執(zhí)行如下幾種狀態(tài):

    • START_SUCCESS 代表Activity啟動(dòng)成功。往往這種情況下骡澈,很少會(huì)遇到锅纺。一般是進(jìn)程在啟動(dòng)的時(shí)候,被阻塞起來肋殴。直到進(jìn)程啟動(dòng)后囤锉,執(zhí)行了加入棧的處理設(shè)置了狀態(tài)碼為START_TASK_TO_FRONT后,解開阻塞护锤。進(jìn)入到START_TASK_TO_FRONT中.

    • START_DELIVERED_TO_TOP 代表存在的Activity重新回到頂部

    • START_TASK_TO_FRONT 并沒真正的啟動(dòng)Activity官地,但是Activity對(duì)應(yīng)的棧跑到用戶交互前臺(tái)。而這個(gè)過程中烙懦,又會(huì)阻塞整個(gè)AMS驱入,直到這個(gè)Activity可視化為止。

能看到AMS比起之前來說氯析,約束了整個(gè)Binder通信的吞吐量亏较。從創(chuàng)建到加入Activity棧凡人,再到可視化都變成了一環(huán)扣著一環(huán)的了烛缔。這么做確實(shí)可以減少那些不可見的(不怎么緊急的)Activity啟動(dòng)膘格,占用過多系統(tǒng)資源么鹤。

  • 4.從進(jìn)程LRU緩存中邢隧,查找這些進(jìn)程中是否有對(duì)應(yīng)的ActivityRecord是否已經(jīng)存在在某一個(gè)棧旋廷。從ActivityDisplay中的ActivityStack尋找ActivityRecord
Android進(jìn)程LRU緩存調(diào)整.png
  • 5.處理Intent的Flag:FORWARD_RESULT.這個(gè)標(biāo)志位就是透?jìng)鱮equestCode時(shí)候的行為膛虫。一般是中間有一個(gè)臨時(shí)的Activity鹃祖,此時(shí)必定可以找到啟動(dòng)這個(gè)臨時(shí)Activity的Activity對(duì)應(yīng)的ActivityRecord,并且設(shè)置ActivityRecordsourceRecord,并獲取sourceRecord中的requestCoderesultWho作為參數(shù)進(jìn)行覆蓋。并要把獲取當(dāng)前臨時(shí)Activity的棧作為新的Activity啟動(dòng)對(duì)應(yīng)的棧扁达。

  • 6.判斷當(dāng)前的啟動(dòng)權(quán)限正卧,判斷條件有三:是被判斷為應(yīng)用有害;被禁止啟動(dòng)的進(jìn)程;被設(shè)置為靜音模式跪解,只要不通過都是啟動(dòng)失敗

  • 7.根據(jù)requestCode炉旷,resultWhoActivityInfo等關(guān)鍵信息生成一個(gè)新的ActivityRecord

進(jìn)程優(yōu)先級(jí)

說起進(jìn)程叉讥,大致分為如下幾個(gè)adj優(yōu)先級(jí)級(jí)別:
注意每個(gè)版本的都可能數(shù)值不一樣窘行,這里是Android 9.0版本的:

ADJ級(jí)別 取值 解釋
UNKNOWN_ADJ 1001 一般是指緩存進(jìn)程也就是空進(jìn)程
CACHED_APP_MAX_ADJ 906 不可見進(jìn)程的adj最大值
CACHED_APP_MIN_ADJ 900 不可見進(jìn)程的adj最小值
SERVICE_B_ADJ 800 B List中的Service(較老的、使用可能性更型疾帧)
PREVIOUS_APP_ADJ 700 上一個(gè)App的進(jìn)程(往往通過按返回鍵)
HOME_APP_ADJ 600 Home 進(jìn)程
SERVICE_ADJ 500 包含Service的服務(wù)進(jìn)程
HEAVY_WEIGHT_APP_ADJ 400 后臺(tái)的重量級(jí)進(jìn)程罐盔,system/rootdir/init.rc文件中設(shè)置
BACKUP_APP_ADJ 300 備份進(jìn)程
PERCEPTIBLE_APP_ADJ 200 可感知進(jìn)程(后臺(tái)服務(wù)播放音樂等)
VISIBLE_APP_ADJ 100 可見進(jìn)程
FOREGROUND_APP_ADJ 0 前臺(tái)進(jìn)程
PERSISTENT_SERVICE_ADJ -700 關(guān)聯(lián)著系統(tǒng)或persistent進(jìn)程
PERSISTENT_PROC_ADJ -800 系統(tǒng)persistent進(jìn)程,比如telephony電話
SYSTEM_ADJ -900 系統(tǒng)進(jìn)程
NATIVE_ADJ -1000 native 進(jìn)程救崔,不受系統(tǒng)管控 如從init.cpp中fork出來的,如內(nèi)核線程等等

總結(jié)下來惶看,面試中常問的Android中進(jìn)程優(yōu)先級(jí),一般可以分為如下幾種:

  • 1.前臺(tái)進(jìn)程
  • 2.可視進(jìn)程
  • 3.服務(wù)進(jìn)程
  • 4.后臺(tái)進(jìn)程
  • 5.空進(jìn)程

從上至下六孵,進(jìn)程重要的等級(jí)越來越低纬黎,等級(jí)越低的adj數(shù)值越高,越高adj的數(shù)值越有可能被lmk 也就是lowmemorykiller 進(jìn)程通過某種策略殺掉劫窒。

對(duì)應(yīng)Android系統(tǒng)來說本今,UNKNOWN_ADJ 說明此時(shí)進(jìn)程的優(yōu)先級(jí)不明確,在調(diào)整adj的時(shí)候主巍,并不會(huì)通知lmk進(jìn)程處理這個(gè)進(jìn)程冠息。

把這5個(gè)進(jìn)程等級(jí)拆分出來稍微解釋一下。所有調(diào)整adj數(shù)值都在computeOomAdjLocked方法中

前臺(tái)進(jìn)程

是指當(dāng)前用戶必須執(zhí)行的進(jìn)程孕索。只有進(jìn)程真的沒內(nèi)存了逛艰,才會(huì)殺掉。一般是指adj等級(jí)為FOREGROUND_APP_ADJ

  if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
...
        } else if (app.runningRemoteAnimation) {
...
        } else if (app.instr != null) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
...
        } else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
...
        } else if (app.executingServices.size() > 0) {
.
            adj = ProcessList.FOREGROUND_APP_ADJ;
...
        } else if (app == TOP_APP) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
...
        }
...

            if (cpr.hasExternalProcessHandles()) {
                if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                    adj = ProcessList.FOREGROUND_APP_ADJ;
...
            }

從上面可知搞旭,滿足前臺(tái)進(jìn)程的的情況如下:

  • 1.正在交互的Activity瓮孙,也就是當(dāng)前的Activity正在onResume的生命周期
  • 2.某個(gè)進(jìn)程正在被profile監(jiān)聽
  • 3.某個(gè)Service綁定到用戶正在交互的Activity
  • 4.某個(gè)進(jìn)程擁有并執(zhí)行了調(diào)用了startForeground的前臺(tái)服務(wù)
  • 5.某個(gè)進(jìn)程的廣播接收器正在接受消息
  • 6.如果某個(gè)非系統(tǒng)進(jìn)程的ContentProvider的進(jìn)程正在被依賴其他進(jìn)程依賴獲取數(shù)據(jù),也是前臺(tái)進(jìn)程
  • 7.擁有正執(zhí)行一個(gè)生命周期回調(diào)的 Service(onCreate()选脊、onStart() 或 onDestroy())

可見進(jìn)程

雖然沒有任何前臺(tái)的組件(指交互中的Activity,接收消息中的Receiver脸甘,被依賴獲取數(shù)據(jù)的CP恳啥,前臺(tái)服務(wù)等),但是依然會(huì)影響屏幕上的內(nèi)容丹诀。在這里是指VISIBLE_APP_ADJ

 else if (app.runningRemoteAnimation) {
            adj = ProcessList.VISIBLE_APP_ADJ;
...
        } 
                if (r.visible) {
                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                        adj = ProcessList.VISIBLE_APP_ADJ;
...
                    }
            for (int conni = s.connections.size()-1;
                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                            || procState > ActivityManager.PROCESS_STATE_TOP);
                    conni--) {
...
                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                                        newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
                                    } else {
                                        newAdj = adj;
                                    }
...
}
  • 1.擁有不再前臺(tái)钝的,但是可見也就是onPause的Activity
  • 2.擁有或者綁定到前臺(tái)或者可見Activity的Service
  • 3.正在執(zhí)行遠(yuǎn)程組件動(dòng)畫的進(jìn)程

服務(wù)進(jìn)程

一般是指與用戶所見內(nèi)容沒有直接的關(guān)聯(lián)翁垂,但是他們通常正在執(zhí)行用戶關(guān)心的任務(wù)(如后臺(tái)播放音樂,或者從網(wǎng)絡(luò)下載數(shù)據(jù))硝桩。
這里的adj是指 PERCEPTIBLE_APP_ADJ

if (r.visible) {
...
                } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                        app.adjType = "pause-activity";
                    }
                    if (procState > PROCESS_STATE_CUR_TOP) {
                        procState = PROCESS_STATE_CUR_TOP;
                        app.adjType = "pause-activity";
                    }
                    if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                    }
                    app.cached = false;
                    app.empty = false;
                    foregroundActivities = true;
                } else if (r.isState(ActivityState.STOPPING)) {
                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                        app.adjType = "stop-activity";
                    }
...
                    app.cached = false;
                    app.empty = false;
                    foregroundActivities = true;
                } else {
...
                }
            }
  • 1.不可見的Activity沿猜,并且是正在執(zhí)行onPause或者onPause執(zhí)行完畢
  • 2.不可見的Activity,且是正在執(zhí)行onStop
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
            if (app.foregroundServices) {
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                app.cached = false;
                app.adjType = "fg-service";
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;

            } else if (app.hasOverlayUi) {
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
                app.cached = false;
                app.adjType = "has-overlay-ui";
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;

            }
        }

        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
            if (app.forcingToImportant != null) {
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
                app.cached = false;
                app.adjType = "force-imp";
                app.adjSource = app.forcingToImportant;
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            }
        }
  • 3.adj優(yōu)先級(jí)低于PERCEPTIBLE_APP_ADJ碗脊,且比 擁有前臺(tái)服務(wù)進(jìn)程的優(yōu)先級(jí)低啼肩,則判斷是否持有前臺(tái)服務(wù),持有也會(huì)設(shè)置為PERCEPTIBLE_APP_ADJ衙伶;如果當(dāng)前的進(jìn)程在執(zhí)行OverlayUi也會(huì)設(shè)置為PERCEPTIBLE_APP_ADJ祈坠。

  • 4.adj優(yōu)先級(jí)低于PERCEPTIBLE_APP_ADJ,且進(jìn)程狀態(tài)等級(jí)低于PROCESS_STATE_TRANSIENT_BACKGROUND正在運(yùn)行的后臺(tái)服務(wù)的進(jìn)程,此時(shí)發(fā)現(xiàn)ProcessRecord持有一個(gè)forcingToImportant的token矢劲。這個(gè)token的設(shè)置實(shí)際是當(dāng)我們需要顯示Toast時(shí)候調(diào)用NotificationManagerServiceenqueueToast入隊(duì)排序顯示吐司赦拘,為了顯示Toast此時(shí)Android系統(tǒng)為了可以正常顯示,就會(huì)調(diào)用keepProcessAliveIfNeededLocked 設(shè)置進(jìn)程對(duì)應(yīng)的token 保證進(jìn)程在最低限度的存活芬沉。

  • 5.通過startService正在運(yùn)行的進(jìn)程.在這些進(jìn)程中找到那些最近顯示過ui的但是現(xiàn)在沒有顯示的躺同,或者此時(shí)沒有顯示ui進(jìn)程且沒有顯示toast的進(jìn)程,都降級(jí)為PERCEPTIBLE_APP_ADJ.

            for (int conni = s.connections.size()-1;
                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                            || procState > ActivityManager.PROCESS_STATE_TOP);
                    conni--) {
                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
                for (int i = 0;
                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                                || procState > ActivityManager.PROCESS_STATE_TOP);
                        i++) {
                    if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
                        if (adj > clientAdj) {
                            if (app.hasShownUi && app != mHomeProcess
                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
...
                            } else {
                                int newAdj;
                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                        |Context.BIND_IMPORTANT)) != 0) {
                                    if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
                                       ...
                                    } else {
                                        newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
                                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                        procState = ActivityManager.PROCESS_STATE_PERSISTENT;
                                    }
                                } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
                                } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
                                   ...
                                } else {
                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
                                        newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
                                    } else {
                                        newAdj = adj;
                                    }
                                }
                                if (!client.cached) {
                                    app.cached = false;
                                }
                                if (adj >  newAdj) {
                                    adj = newAdj;
                                    adjType = "service";
                                }
                            }
                        }
                    }
  }
}

后臺(tái)進(jìn)程

后臺(tái)進(jìn)程對(duì)用戶體驗(yàn)沒有任何影響丸逸,因此進(jìn)程可能會(huì)隨時(shí)回收掉這種進(jìn)程蹋艺,以獲得更多的內(nèi)存。通常會(huì)有很多后臺(tái)進(jìn)程正在運(yùn)行椭员,這些進(jìn)程都會(huì)保存在我剛剛說的LRU表中车海。如果Activity正常的執(zhí)行了生命周期并且緩存了狀態(tài),當(dāng)終止進(jìn)程時(shí)不會(huì)產(chǎn)生明顯用戶體驗(yàn)的影響隘击,當(dāng)通過導(dǎo)航重新打開侍芝,Activity將會(huì)讀取緩存并可見。

在這里adj是指從BACKUP_APP_ADJ 一直到SERVICE_B_ADJ中間埋同。但是只有HOME_APP_ADJ桌面進(jìn)程例外州叠。這個(gè)過程有什么魔法呢?實(shí)際上是在lmkd進(jìn)程通信到lowmemorykiller內(nèi)核模塊(驅(qū)動(dòng))之前凶赁,對(duì)600數(shù)值對(duì)應(yīng)的adj數(shù)值進(jìn)行了特殊處理咧栗,強(qiáng)制設(shè)置為200.
/system/core/lmkd/lmkd.c

static void cmd_procprio(LMKD_CTRL_PACKET packet) {
    struct proc *procp;
    char path[80];
    char val[20];
    int soft_limit_mult;
    struct lmk_procprio params;

    lmkd_pack_get_procprio(packet, &params);

    if (params.oomadj < OOM_SCORE_ADJ_MIN ||
        params.oomadj > OOM_SCORE_ADJ_MAX) {
        ALOGE("Invalid PROCPRIO oomadj argument %d", params.oomadj);
        return;
    }

    snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
    snprintf(val, sizeof(val), "%d", params.oomadj);
    writefilestring(path, val);

    if (use_inkernel_interface)
        return;

    if (low_ram_device) {
        if (params.oomadj >= 900) {
            soft_limit_mult = 0;
        } else if (params.oomadj >= 800) {
            soft_limit_mult = 0;
        } else if (params.oomadj >= 700) {
            soft_limit_mult = 0;
        } else if (params.oomadj >= 600) {
            // Launcher should be perceptible, don't kill it.
            params.oomadj = 200;
            soft_limit_mult = 1;
        } else if (params.oomadj >= 500) {
            soft_limit_mult = 0;
        } else if (params.oomadj >= 400) {
            soft_limit_mult = 0;
        } else if (params.oomadj >= 300) {
            soft_limit_mult = 1;
        } else if (params.oomadj >= 200) {
            soft_limit_mult = 2;
        } else if (params.oomadj >= 100) {
            soft_limit_mult = 10;
        } else if (params.oomadj >=   0) {
            soft_limit_mult = 20;
        } else {
            // Persistent processes will have a large
            // soft limit 512MB.
            soft_limit_mult = 64;
        }

        snprintf(path, sizeof(path),
             "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
             params.uid, params.pid);
        snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
        writefilestring(path, val);
    }

    procp = pid_lookup(params.pid);
    if (!procp) {
            procp = malloc(sizeof(struct proc));
            if (!procp) {
                // Oh, the irony.  May need to rebuild our state.
                return;
            }

            procp->pid = params.pid;
            procp->uid = params.uid;
            procp->oomadj = params.oomadj;
            proc_insert(procp);
    } else {
        proc_unslot(procp);
        procp->oomadj = params.oomadj;
        proc_slot(procp);
    }
}

注意這里面的oomadj參數(shù)就是設(shè)置給lowmemorykiller 驅(qū)動(dòng)參數(shù)。在Android的Linux內(nèi)核中虱肄,每一個(gè)task_struct都包含了一個(gè)signal_struct致板,其中就包含了進(jìn)程的優(yōu)先級(jí)oom_score_adj

空進(jìn)程

就是已經(jīng)什么都不存了咏窿,存儲(chǔ)只是緩存起來的進(jìn)程對(duì)象斟或,縮短下次在其中運(yùn)行組件所需的啟動(dòng)時(shí)間。

代表的adj數(shù)值是CACHED_APP_MIN_ADJCACHED_APP_MAX_ADJ

lmk lowmemorykiller 驅(qū)動(dòng)原理

稍微總結(jié)一下lmkd守護(hù)進(jìn)程 是如何根據(jù)adj殺死無用進(jìn)程的集嵌。
如下圖:


lmkd.png

整個(gè)lmk的流程需要從這幾個(gè)方向上理解萝挤。調(diào)整adj的時(shí)機(jī)有兩個(gè):

  • 1.WMS的配置發(fā)生了配置御毅,此時(shí)就會(huì)調(diào)用updateOomLevels刷新每一個(gè)進(jìn)程的OOM等級(jí)核心計(jì)算方式如下:
    private final int[] mOomAdj = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
    };
    // These are the low-end OOM level limits.  This is appropriate for an
    // HVGA or smaller phone with less than 512MB.  Values are in KB.
    private final int[] mOomMinFreeLow = new int[] {
            12288, 18432, 24576,
            36864, 43008, 49152
    };
    // These are the high-end OOM level limits.  This is appropriate for a
    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
    private final int[] mOomMinFreeHigh = new int[] {
            73728, 92160, 110592,
            129024, 147456, 184320
    };
    // The actual OOM killer memory levels we are using.
    private final int[] mOomMinFree = new int[mOomAdj.length];

首先,lmk只會(huì)處理FOREGROUND_APP_ADJ,VISIBLE_APP_ADJ,PERCEPTIBLE_APP_ADJ,BACKUP_APP_ADJ怜珍,CACHED_APP_MIN_ADJ,CACHED_APP_MAX_ADJ 這6個(gè)級(jí)別的adj對(duì)應(yīng)的進(jìn)程端蛆。

每一次WMS的配置發(fā)生了變更,也就是屏幕相關(guān)的信息發(fā)生了變化酥泛,每一個(gè)進(jìn)程可用的最小內(nèi)存也會(huì)隨之發(fā)生變化今豆,計(jì)算公式如下:

LMK殺死進(jìn)程的閾值 = mOomMinFreeLow[對(duì)應(yīng)adj等級(jí)在mOomAdj的index] + (mOomMinFreeHigh[對(duì)應(yīng)adj等級(jí)在mOomAdj的index] - mOomMinFreeLow[對(duì)應(yīng)adj等級(jí)在mOomAdj的index])* scale

比如說:

此時(shí)是CACHED_APP_MAX_ADJ,在mOomMinFreeLow對(duì)應(yīng)的內(nèi)存是49152揭璃,在mOomMinFreeHigh對(duì)應(yīng)的是184320晚凿,則:49152+(184320-49152)*scale

這個(gè)scale數(shù)值的計(jì)算是根據(jù)屏幕狀態(tài)變化而變化:

scaleMem(內(nèi)存系數(shù)) = (系統(tǒng)的總內(nèi)存(單位MB) - 350)/ 350
scaleDisp(屏幕內(nèi)存系數(shù)) = ((屏幕寬*屏幕高) - (480 * 800)) / ((1280 * 800) - (480 * 800))

實(shí)際上第一個(gè)內(nèi)存系數(shù)就是獲取當(dāng)前內(nèi)存以350M為一個(gè)單位看看還有多少份;第二個(gè)屏幕內(nèi)存系數(shù)是看看一個(gè)屏幕下總像素的內(nèi)存進(jìn)行均值化 (有興趣可以看看線性回歸與梯度下降)從而獲得屏幕像素歸一到(480 * 800) (最小屏幕大小)和(1280 * 800) 最大屏幕大小(很明顯現(xiàn)實(shí)中比最大的大瘦馍,比最小的小比比皆是)歼秽,從而獲得一個(gè)合適的像素內(nèi)存系數(shù)。

比較兩者取較大的數(shù)值

scale = scaleMem > scaleDisp ? scaleMem : scaleDisp

最后把計(jì)算出來的對(duì)應(yīng)的adj對(duì)應(yīng)的最小內(nèi)存保存到mOomMinFree數(shù)組中發(fā)送到lowmemorykiller驅(qū)動(dòng)中緩存起來情组。

  • 2.當(dāng)進(jìn)程中四大組件的行為發(fā)生了變更燥筷,則會(huì)每一個(gè)進(jìn)程對(duì)應(yīng)adj數(shù)值。此時(shí)會(huì)先通過socket通信到lmkd守護(hù)進(jìn)程中院崇,此時(shí)會(huì)通過Linux的cgroup把當(dāng)前對(duì)應(yīng)的內(nèi)存限額寫入對(duì)應(yīng)的進(jìn)程中肆氓。等到內(nèi)核需要回收的時(shí)候,就會(huì)通過lowkmemorykiller遍歷找到最大的rss內(nèi)存底瓣,最大的adj通過發(fā)送中斷信號(hào)SIGKILL殺死進(jìn)程谢揪。

Activity 棧的變化

要徹底弄明白Activity的棧變化需要了解如下數(shù)據(jù)結(jié)構(gòu),可以閱讀我寫過的WMS在Activity啟動(dòng)中的職責(zé)(二)一文捐凭,里面介紹了不僅僅是Activity啟動(dòng)時(shí)候拨扶,對(duì)應(yīng)棧的數(shù)據(jù)結(jié)構(gòu),還對(duì)應(yīng)了WMS如何控制這些數(shù)據(jù)結(jié)構(gòu)的顯示:

ConfigurationContainer之間聯(lián)系.png

先從這個(gè)圖中關(guān)鍵的四個(gè)的數(shù)據(jù)結(jié)構(gòu)開始說起:

    1. ActivityDisplay 代表每一個(gè)Activity顯示的顯示屏茁肠,內(nèi)持有邏輯顯示屏對(duì)應(yīng)的id患民。這個(gè)對(duì)象將會(huì)持有三個(gè)核心的數(shù)據(jù)結(jié)構(gòu)DisplayWindowController,DisplayContent,ActivityStack.前兩者控制整個(gè)棧對(duì)應(yīng)的顯示區(qū)域如何擺放.后者則是以一個(gè)應(yīng)用進(jìn)程的維度控制棧
    1. ActivityStack 是指進(jìn)程中有多少個(gè)Activity的棧。這個(gè)棧持有了一個(gè)mHistory集合垦梆。這個(gè)棧才是正常開發(fā)中接觸到的棧匹颤。
  • 3.TaskRecord 就是我們開發(fā)中接觸的棧,這個(gè)棧持有了taskid托猩,affinity等標(biāo)識(shí)參數(shù)印蓖。其中持有一個(gè)核心數(shù)據(jù)結(jié)構(gòu)mActivities的集合mActivities

  • 4.ActivityRecord 實(shí)際上就是Activity在AMS中標(biāo)示對(duì)象京腥。系統(tǒng)通過持有ActivityRecord從而得知每一個(gè)應(yīng)用進(jìn)程中每一個(gè)Activity的狀態(tài)另伍。

如下圖:

AMS棧的設(shè)計(jì).png

對(duì)于我們開發(fā)者來說只有TaskRecord才是可見的。

理解了這些之后,在方法startActivityUnchecked會(huì)處理絕大部分的關(guān)于Task相關(guān)的操作摆尝。

回顧一下Activity四大啟動(dòng)模式:

  • 1.standard 意味著默認(rèn)啟動(dòng)方式。繼承上一個(gè)Activity對(duì)應(yīng)的Task進(jìn)行啟動(dòng)
  • 2.singleTop 如果Activity處于棧頂則不需要?jiǎng)?chuàng)建因悲,不在棧頂則創(chuàng)建新的堕汞。意味這這里的棧頂也就是TaskRecord的mActivities處于末尾頂部
  • 3.singleTask 是指棧內(nèi)唯一,此時(shí)會(huì)從TaskRecord的mActivities中查找能否有復(fù)用的ActivityRecord
  • 4.singleInstance 這個(gè)是指新建一個(gè)TaskRecord保存在mTaskHistory中晃琳,并新建一個(gè)新的ActivityRecord讯检。

實(shí)際上AMS,并不是根據(jù)這四個(gè)啟動(dòng)模式進(jìn)行處理的卫旱。而是這四個(gè)啟動(dòng)模式人灼,會(huì)轉(zhuǎn)化成Intent中對(duì)應(yīng)的flag進(jìn)行出來。

其實(shí)很簡(jiǎn)單顾翼,如果我們忽略了分屏操作的行為投放,實(shí)際上在AMS眼里可以把啟動(dòng)帶上的flag分為如下四類:

  • 1.如果是啟動(dòng)的flag打上了FLAG_ACTIVITY_NEW_TASK,調(diào)用setTaskFromReuseOrCreateNewTask
  • 2.繼承上一個(gè)ActivityRecord對(duì)應(yīng)的TaskRecord 調(diào)用setTaskFromSourceRecord
  • 3.不繼承上一個(gè)ActivityRecordTaskRecord,但是因?yàn)橹付?code>TaskRecord的affinity,id等方式提前得知了對(duì)應(yīng)的TaskRecord,從而移動(dòng)到另一個(gè)TaskRecord 調(diào)用setTaskFromInTask
  • 4.其他模式 調(diào)用setTaskToCurrentTopOrCreateNewTask

第三點(diǎn)适贸,是系統(tǒng)內(nèi)部調(diào)用startActivityInPackage時(shí)候明確知道TaskRecord是什么灸芳。我們不去討論。

setTaskFromReuseOrCreateNewTask

這個(gè)方法就是專門處理FLAG_ACTIVITY_NEW_TASK 標(biāo)志位的拜姿。

在執(zhí)行這個(gè)判斷之前烙样,會(huì)調(diào)用computeLaunchingTaskFlags方法判斷調(diào)用startActivity的調(diào)用者,是否存在啟動(dòng)的Activity對(duì)象且沒有確定的TaskRecord(mInTask)蕊肥,此時(shí)就是谒获。

-沒有復(fù)用的TaskRecord : 在setTaskFromReuseOrCreateNewTask這個(gè)方法就會(huì)創(chuàng)建一個(gè)新的TaskRecord.在準(zhǔn)備的步驟,已經(jīng)找到對(duì)應(yīng)的ActivityRecord.壁却,或者創(chuàng)建一個(gè)全新的ActivityRecord.就會(huì)調(diào)用addOrReparentStartingActivity 綁定這個(gè)全新的TaskRecord.

  • 存在復(fù)用TaskRecord :則直接調(diào)用addOrReparentStartingActivity 重新綁定TaskRecord.從而實(shí)現(xiàn)棧內(nèi)唯一批狱。指的注意的是,如果此時(shí)的launchModeLAUNCH_SINGLE_INSTANCE 或者LAUNCH_SINGLE_TASK 則強(qiáng)制把對(duì)應(yīng)的登錄flag添加一個(gè)FLAG_ACTIVITY_NEW_TASK.

setTaskFromSourceRecord

這個(gè)過程中儒洛,就會(huì)獲得調(diào)用者ActivityRecordTaskRecord以及ActivityStack,新的ActivityRecord并準(zhǔn)備繼承這些對(duì)象精耐。

    1. 判斷是否帶上FLAG_ACTIVITY_CLEAR_TOP標(biāo)志位且不需要添加到TaskRecord,帶則調(diào)用TaskRecordperformClearTaskLocked 調(diào)用這個(gè)方法調(diào)用之前復(fù)用ActivityRecord之前的所有Activity的finish的方法琅锻。
  • 2.并把對(duì)應(yīng)的ActivityStack卦停,TaskRecord移動(dòng)到集合的末尾,作為當(dāng)前的焦點(diǎn)恼蓬。

  • 3.addOrReparentStartingActivity綁定或者新增到TaskRecord中

setTaskToCurrentTopOrCreateNewTask

    private void setTaskToCurrentTopOrCreateNewTask() {
        mTargetStack = computeStackFocus(mStartActivity, false, mLaunchFlags, mOptions);
        if (mDoResume) {
            mTargetStack.moveToFront("addingToTopTask");
        }
        final ActivityRecord prev = mTargetStack.getTopActivity();
        final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
                mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
                mIntent, null, null, true, mStartActivity, mSourceRecord, mOptions);
        addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
        mTargetStack.positionChildWindowContainerAtTop(task);
    }

其他情況就是拿到焦點(diǎn)的ActivityStack后再拿到頂部運(yùn)行的TaskRecord惊完,把新的ActivityRecord綁定起來。

Activity跨進(jìn)程啟動(dòng)

在方法realStartActivityLocked中真正的開始進(jìn)行跨進(jìn)程通信处硬,在繼續(xù)聊之前看看幾個(gè)重要的對(duì)象:

ClientTransaction.png

ClientTransaction 是AMS通信到App應(yīng)用進(jìn)程的核心對(duì)象小槐。

  • 1.ClientTransaction 客戶端事務(wù)控制者
  • 2.ClientLifecycleManager 客戶端的生命周期事務(wù)控制者
  • 3.TransactionExecutor 遠(yuǎn)程通信事務(wù)執(zhí)行者
  • 4.LaunchActivityItem 遠(yuǎn)程App端的onCreate生命周期事務(wù)
  • 5.ResumeActivityItem 遠(yuǎn)程App端的onResume生命周期事務(wù)
  • 6.PauseActivityItem 遠(yuǎn)程App端的onPause生命周期事務(wù)
  • 7.StopActivityItem 遠(yuǎn)程App端的onStop生命周期事務(wù)
  • 8.DestroyActivityItem 遠(yuǎn)程App端onDestroy生命周期事務(wù)。
  • 9.ClientTransactionHandler App端對(duì)ClientTransaction的處理。

LaunchActivityItem

LaunchActivityItem 通信到在AppThread做了如下事情:

  • 1.反射生成Activity實(shí)例
  • 2.獲取當(dāng)前的應(yīng)用的Application對(duì)象并且調(diào)用attach綁定
  • 3.最后通過Instrument調(diào)用callActivityOnCreate調(diào)用到Activity實(shí)例中的onCreate方法

ResumeActivityItem

  • 1.調(diào)用ActivityThreadhandleStartActivity,執(zhí)行ActivityonStart方法
  • 2.調(diào)用ActivityThreadperformResumeActivity
  • 3.如果pendingIntent不為空凿跳,則以此執(zhí)行執(zhí)行onNewIntent,onActivityResult
  • 4.執(zhí)行ActivityonResume
  • 5.執(zhí)行View的繪制流程
  • 6.執(zhí)行handler的idle事件件豌,這個(gè)事件就是Idler對(duì)象。關(guān)于idle相關(guān)的內(nèi)容可以閱讀Handler與相關(guān)系統(tǒng)調(diào)用的剖析(上).這個(gè)事件就是Handler沒有什么重要事件執(zhí)行的控嗜,執(zhí)行的內(nèi)容就是activityIdle這個(gè)方法就會(huì)調(diào)用所有不可見Activity的onStop

PauseActivityItem

  • 1.Android3.0之前調(diào)用callActivityOnSaveInstanceState方法保存當(dāng)前Activity的狀態(tài)
  • 2.調(diào)用ActivityonPause
  • 3.此時(shí)一旦判斷當(dāng)前ActivityRecord已經(jīng)綁定了App端的數(shù)據(jù)茧彤,說明已經(jīng)啟動(dòng)了,并且當(dāng)前的ActivityRecord的visible為false疆栏,或者點(diǎn)擊了鎖屏使其睡眠曾掂,都會(huì)調(diào)用addToStopping.到activityIdle方法就會(huì)執(zhí)行Activity的onStop,因此如果是可見的dialog壁顶,由于此時(shí)Activity還是可見珠洗,因此不會(huì)走到onStop方法

StopActivityItem

  • 1.調(diào)用過ActivityThread的handleStopActivity方法
  • 2.如果沒有調(diào)用過onPause 則調(diào)用onPause
  • 3.調(diào)用ActivityonStop
  • 4.等待SP寫入磁盤
  • 5.執(zhí)行AMS的activityStopped,在activityStoppedLocked里面判斷ActivityRecord是否通過makeFinishingLocked設(shè)置了finishing為true若专,從而判斷是否需要執(zhí)行后續(xù)的周期许蓖。

DestroyActivityItem

當(dāng)調(diào)用了Activity的finish方法后,就會(huì)跨進(jìn)程調(diào)用的finishActivity:

  • 1.當(dāng)前要finish的Activity剛好就是當(dāng)前的正在交互的Activity富岳,則調(diào)用onPauseonStop,調(diào)用ActivityStackdestroyActivityLocked

  • 2.當(dāng)finish的Activity不是onPause蛔糯,嘗試調(diào)用finishCurrentActivityLocked,finish對(duì)應(yīng)的Activity,接著會(huì)嘗試的調(diào)用addToStopping窖式,會(huì)調(diào)到onStop方法蚁飒,接著也會(huì)調(diào)用destroyActivityLocked。

  • 3.執(zhí)行DestroyActivityItem中對(duì)應(yīng)的跨進(jìn)程操作

  • 4.調(diào)用Activity的OnDestroy

  • 5.將會(huì)清空Activity中設(shè)置的window數(shù)據(jù)以及設(shè)置的ContentView

  • 6.最后通過activityDestroyed通知AMS

onRestart

肯定有人覺得奇怪萝喘,七大聲明周期之一的onRestart呢淮逻?他其實(shí)和onStart一樣隱藏在TransactionExecutor 中。
來看看/frameworks/base/core/java/android/app/servertransaction/TransactionExecutorHelper.java

   public IntArray getLifecyclePath(int start, int finish, boolean excludeLastState) {
        if (start == UNDEFINED || finish == UNDEFINED) {
            throw new IllegalArgumentException("Can't resolve lifecycle path for undefined state");
        }
        if (start == ON_RESTART || finish == ON_RESTART) {
            throw new IllegalArgumentException(
                    "Can't start or finish in intermittent RESTART state");
        }
        if (finish == PRE_ON_CREATE && start != finish) {
            throw new IllegalArgumentException("Can only start in pre-onCreate state");
        }

        mLifecycleSequence.clear();
        if (finish >= start) {
            // just go there
...
        } else { // finish < start, can't just cycle down
            if (start == ON_PAUSE && finish == ON_RESUME) {
                // Special case when we can just directly go to resumed state.
                mLifecycleSequence.add(ON_RESUME);
            } else if (start <= ON_STOP && finish >= ON_START) {
                // Restart and go to required state.

                // Go to stopped state first.
                for (int i = start + 1; i <= ON_STOP; i++) {
                    mLifecycleSequence.add(i);
                }
                // Restart
                mLifecycleSequence.add(ON_RESTART);
                // Go to required state
                for (int i = ON_START; i <= finish; i++) {
                    mLifecycleSequence.add(i);
                }
            } else {
                // Relaunch and go to required state

                // Go to destroyed state first.
                for (int i = start + 1; i <= ON_DESTROY; i++) {
                    mLifecycleSequence.add(i);
                }
                // Go to required state
                for (int i = ON_CREATE; i <= finish; i++) {
                    mLifecycleSequence.add(i);
                }
            }
        }

...
        return mLifecycleSequence;
    }

注意這里的參數(shù)start是指當(dāng)前Activity的狀態(tài)阁簸,finish是指經(jīng)過TransactionExecutor執(zhí)行后爬早,每一個(gè)ActivityLifecycleItem對(duì)應(yīng)的目標(biāo)Activity需要達(dá)到什么聲明周期。

  • 1.如果當(dāng)前的Activity是ON_PAUSE狀態(tài)启妹,目標(biāo)是ON_RESUME筛严,此時(shí)只需要執(zhí)行一個(gè)ON_RESUME

  • 2.如果此時(shí)的狀態(tài)是ON_STOP之后的狀態(tài),且目標(biāo)是ON_START.一般來說此時(shí)都是執(zhí)行的是ResumeActivityItem 需要從AMS讓此時(shí)的Activity轉(zhuǎn)化為可見饶米。此時(shí)的Activity已經(jīng)執(zhí)行了onStop桨啃,就會(huì)把小于ON_STOP的狀態(tài)添加進(jìn)來(沒有就跳過了),再把ON_RESTART聲明周期添加進(jìn)來,最后把onStartonResume(因?yàn)?code>ResumeActivityItem 目標(biāo)就是onResume)添加進(jìn)來

  • 3.最后到達(dá)了TransactionExecutor中執(zhí)行每一個(gè)ActivityLifecycleItem的生命周期檬输,從而執(zhí)行了ActivityThread的onRestart后執(zhí)行照瘾,onStart,onResume

實(shí)際案例

有一道常見的面試題:

  • Activity A 啟動(dòng) Activity B 聲明周期怎么執(zhí)行
  • Activity B 在onCreate,onResume執(zhí)行finish是怎么執(zhí)行聲明周期的丧慈。

第一種情況下:A啟動(dòng)了B析命。

此時(shí)A會(huì)先執(zhí)行PauseActivityItem,從而執(zhí)行onPause,此時(shí)AMS會(huì)阻塞住不會(huì)前往執(zhí)行B的啟動(dòng)。

onPause執(zhí)行結(jié)束之后鹃愤,就會(huì)繼續(xù)執(zhí)行A的onCreate簇搅,onStart,onResume,接著執(zhí)行一個(gè)idle事件,通知AMS執(zhí)行所有不可見的Activity的onStop,如下圖:

2020-09-12 22:44:20.745 9287-9287/com.yjy.superjsbridge E/A: onStart
2020-09-12 22:44:20.747 9287-9287/com.yjy.superjsbridge E/A: onResume
2020-09-12 22:44:31.746 9287-9287/com.yjy.superjsbridge E/A: onPause
2020-09-12 22:44:31.768 9287-9287/com.yjy.superjsbridge E/B: onCreate
2020-09-12 22:44:32.598 9287-9287/com.yjy.superjsbridge E/B: onStart
2020-09-12 22:44:32.603 9287-9287/com.yjy.superjsbridge E/B: onResume
2020-09-12 22:44:33.083 9287-9287/com.yjy.superjsbridge E/A: onStop
2020-09-12 22:54:31.631 9287-9287/com.yjy.superjsbridge E/B: onPause
2020-09-12 22:54:31.688 9287-9287/com.yjy.superjsbridge E/B: onStop

一旦熄掉屏幕后昼浦,重新打開馍资,或者從Home/其他App回來后就會(huì)執(zhí)行:

2020-09-12 23:00:14.342 9287-9287/com.yjy.superjsbridge E/B: onRestart
2020-09-12 23:00:14.418 9287-9287/com.yjy.superjsbridge E/B: onStart
2020-09-12 23:00:14.433 9287-9287/com.yjy.superjsbridge E/B: onResume

第二種:Activity A 在onCreate,onResume執(zhí)行finish是怎么執(zhí)行聲明周期的关噪。其實(shí)就是考察了對(duì)finishActivityLocked的理解。
當(dāng)調(diào)用了finish之后乌妙,會(huì)執(zhí)行如下方法:

            if (mResumedActivity == r) {
....
                r.setVisibility(false);

                if (mPausingActivity == null) {
                    startPausingLocked(false, false, null, pauseImmediately);
                }

                if (endTask) {
                    mService.getLockTaskController().clearLockedTask(task);
                }
            } else if (!r.isState(PAUSING)) {
  ....
                final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
                        : FINISH_AFTER_PAUSE;
                final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
                        "finishActivityLocked") == null;

               ....
                return removedActivity;
            } else {
            }

只分為兩種情況:

  • 當(dāng)前的Activity在onResume使兔,此時(shí)設(shè)置了visible為false,并開始調(diào)用onPause方法藤韵。所以就會(huì)調(diào)用onPause,當(dāng)執(zhí)行完后虐沥,就會(huì)調(diào)用completePauseLocked方法,此時(shí)是不可見的泽艘,就會(huì)添加到addToStop對(duì)象欲险,并且執(zhí)行onStop的方法以及onDestory

  • 如果此時(shí)不是正在執(zhí)行PAUSING。則根據(jù)是否顯示來決定是finish的方法是可視化之后再finish(FINISH_AFTER_VISIBLE)匹涮,另一個(gè)是pause之后在finish(FINISH_AFTER_PAUSE)天试。

    • FINISH_AFTER_VISIBLE 則通過startPausingLocked調(diào)用addToStop,通知AMS的Handler執(zhí)行activityIdleInternalLocked方法然低,這個(gè)方法就是執(zhí)行ActivityThread的onStop的入口喜每。在ActivityThread中會(huì)校驗(yàn)onPause是否執(zhí)行,沒執(zhí)行過則執(zhí)行雳攘,最后執(zhí)行onStop带兜,并在activityIdleInternalLocked的后半段立即返回來執(zhí)行finishActivityLocked方法,此時(shí)就是FINISH_AFTER_PAUSE 的方式
  • FINISH_AFTER_PAUSE 把狀態(tài)設(shè)置為FINISHING吨灭,調(diào)用destroyActivityLocked開始真正執(zhí)行onDestroy周期刚照。發(fā)送一個(gè)Handler消息最后把ActivityRecord從TaskRecord 中移除,如果此時(shí)TaskRecord已經(jīng)不存在ActivityRecord喧兄,則從ActivityStack移除

都是在之前的文章詳細(xì)說過的无畔。

那么,放在這里:

  • 如果B在onCreate執(zhí)行了onDestroy繁莹,此時(shí)走的就是FINISH_AFTER_PAUSE直接finish掉
2020-09-12 23:42:19.043 13942-13942/com.yjy.superjsbridge E/B: onCreate
2020-09-12 23:42:19.921 13942-13942/com.yjy.superjsbridge E/B: onDestroy
  • onStart周期比較特殊檩互,因?yàn)閛nStart是跟在ResumeActivityItem中間走的,但是執(zhí)行到了執(zhí)行完了onStart就設(shè)置為finishing狀態(tài)咨演,導(dǎo)致onResume無法走下去闸昨。此時(shí)相當(dāng)于visible還沒有設(shè)置為true,走的是FINISH_AFTER_PAUSE,直接執(zhí)行onDestroy的周期,注意下面這段代碼,此時(shí)根據(jù)當(dāng)前ActivityClientRecord的標(biāo)志位來決定是否需要補(bǔ)充執(zhí)行onPause饵较,和onStop
    ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        Class<? extends Activity> activityClass = null;
        if (r != null) {
            activityClass = r.activity.getClass();
            r.activity.mConfigChangeFlags |= configChanges;
            if (finishing) {
                r.activity.mFinished = true;
            }

            performPauseActivityIfNeeded(r, "destroy");

            if (!r.stopped) {
                callActivityOnStop(r, false /* saveState */, "destroy");
            }
...
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnDestroy(r.activity);
...
            } catch (SuperNotCalledException e) {
...
            } catch (Exception e) {
...
            }
            r.setState(ON_DESTROY);
        }
        mActivities.remove(token);
        StrictMode.decrementExpectedActivityCount(activityClass);
        return r;
    }

注意拍嵌,每一次聲明周期的執(zhí)行后,都會(huì)調(diào)用如下方法:

        public void setState(@LifecycleState int newLifecycleState) {
            mLifecycleState = newLifecycleState;
            switch (mLifecycleState) {
                case ON_CREATE:
                    paused = true;
                    stopped = true;
                    break;
                case ON_START:
                    paused = true;
                    stopped = false;
                    break;
                case ON_RESUME:
                    paused = false;
                    stopped = false;
                    break;
                case ON_PAUSE:
                    paused = true;
                    stopped = false;
                    break;
                case ON_STOP:
                    paused = true;
                    stopped = true;
                    break;
            }
        }

能發(fā)現(xiàn)onCreate執(zhí)行之后pausedstopped都是true,所以performDestroyActivity不會(huì)補(bǔ)充執(zhí)行onPause,onStop直接執(zhí)行onDestroy.

如果是onStart執(zhí)行之后,paused為true,stopped是false循诉,所以横辆,在`onDestroy補(bǔ)充執(zhí)行onStop

2020-09-12 23:49:07.902 15359-15359/com.yjy.superjsbridge E/B: onCreate
2020-09-12 23:49:08.066 15359-15359/com.yjy.superjsbridge E/B: onStart
2020-09-12 23:49:08.107 15359-15359/com.yjy.superjsbridge E/B: onStop
2020-09-12 23:49:08.107 15359-15359/com.yjy.superjsbridge E/B: onDestroy

如果A在onResume,onPause茄猫,onStop方法執(zhí)行finish,就會(huì)走FINISH_AFTER_VISIBLE 流程狈蚤,依次走完剩下的流程再走onDestroy.

onResume 中finish:

020-09-13 10:15:36.193 1071-1071/com.yjy.superjsbridge E/B: onCreate
2020-09-13 10:15:36.813 1071-1071/com.yjy.superjsbridge E/B: onStart
2020-09-13 10:15:36.818 1071-1071/com.yjy.superjsbridge E/B: onResume
2020-09-13 10:15:36.843 1071-1071/com.yjy.superjsbridge E/B: onPause
2020-09-13 10:15:36.860 1071-1071/com.yjy.superjsbridge E/A: onResume
2020-09-13 10:15:36.894 1071-1071/com.yjy.superjsbridge E/B: onStop
2020-09-13 10:15:36.895 1071-1071/com.yjy.superjsbridge E/B: onDestroy

onPause 中finish:

E/B: onPause
E/B: onStop
E/B: onDestroy

onStop 中finish:

2020-09-13 10:28:10.311 12235-12235/com.yjy.superjsbridge E/B: onPause
2020-09-13 10:28:10.385 12235-12235/com.yjy.superjsbridge E/B: onStop
2020-09-13 10:28:10.654 12235-12235/com.yjy.superjsbridge E/B: onDestroy

同理在onRestart也是類似的,因?yàn)辄c(diǎn)擊了Home等情況,所以已經(jīng)執(zhí)行過了onStop划纽,所以會(huì)繼續(xù)走完下面的周期:

2020-09-13 10:29:43.099 12412-12412/com.yjy.superjsbridge E/B: onRestart
2020-09-13 10:29:43.540 12412-12412/com.yjy.superjsbridge E/B: onDestroy

`

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脆侮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勇劣,更是在濱河造成了極大的恐慌靖避,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件比默,死亡現(xiàn)場(chǎng)離奇詭異幻捏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)命咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門篡九,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人侈百,你說我怎么就攤上這事瓮下。” “怎么了钝域?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵讽坏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我例证,道長(zhǎng)路呜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任织咧,我火速辦了婚禮胀葱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笙蒙。我一直安慰自己抵屿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布捅位。 她就那樣靜靜地躺著轧葛,像睡著了一般搂抒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尿扯,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天求晶,我揣著相機(jī)與錄音,去河邊找鬼衷笋。 笑死芳杏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辟宗。 我是一名探鬼主播爵赵,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼泊脐!你這毒婦竟也來了亚再?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤晨抡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后则剃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耘柱,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年棍现,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了调煎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡己肮,死狀恐怖士袄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谎僻,我是刑警寧澤娄柳,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站艘绍,受9級(jí)特大地震影響赤拒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诱鞠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一挎挖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧航夺,春花似錦蕉朵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冷蚂。三九已至,卻和暖如春觅闽,著一層夾襖步出監(jiān)牢的瞬間帝雇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工蛉拙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尸闸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓孕锄,卻偏偏與公主長(zhǎng)得像吮廉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子畸肆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345