《Android開(kāi)發(fā)藝術(shù)探索》之學(xué)習(xí)筆記(九)四大組件的工作過(guò)程

四大組件概述

  • Activity绎狭,是一種展示型組件细溅,用于向用戶展示UI。它只有一種運(yùn)行模式:處于啟動(dòng)狀態(tài)儡嘶。
  • Service喇聊,是一種計(jì)算型組件,用于在后臺(tái)執(zhí)行一系列計(jì)算任務(wù)蹦狂。它有兩種狀態(tài):?jiǎn)?dòng)狀態(tài)和綁定狀態(tài)誓篱。Service是運(yùn)行在主線程的,因此耗時(shí)的任務(wù)需要在工作線程去完成凯楔。Service處于綁定狀態(tài)時(shí)窜骄,它內(nèi)部同樣可以進(jìn)行后臺(tái)計(jì)算。
  • BroadCastReceiver摆屯,是一種消息行組件邻遏,用于在不同的組件甚至不同應(yīng)用間傳遞消息。靜態(tài)注冊(cè)在應(yīng)用安裝時(shí)會(huì)被系統(tǒng)解析虐骑,不需要應(yīng)用啟動(dòng)就能收到相應(yīng)的廣播准验;動(dòng)態(tài)注冊(cè)必須要應(yīng)用啟動(dòng)后才能收到廣播。
  • ContentProvider廷没,是一種數(shù)據(jù)共享型組件糊饱,用于向其他組件甚至其他應(yīng)用共享數(shù)據(jù)。它對(duì)數(shù)據(jù)集合的具體實(shí)現(xiàn)沒(méi)有要求颠黎,可以是數(shù)據(jù)庫(kù)另锋,List滞项、Map甚至文件等。它內(nèi)部的insert砰蠢、delete蓖扑、update和query方法需要處理好線程同步唉铜,因?yàn)檫@幾個(gè)方法是運(yùn)行在Binder線程池中的台舱。ContentProvider不需要手動(dòng)停止。

Activity的工作過(guò)程

一張圖說(shuō)明Activity的啟動(dòng)流程:


這里寫(xiě)圖片描述

performLaunchActivity這個(gè)方法主要完成如下幾件事:
1潭流、從ActivityClientRecord中獲取待啟動(dòng)的Activity的組件信息

ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
   r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
           Context.CONTEXT_INCLUDE_CODE);
}

ComponentName component = r.intent.getComponent();
if (component == null) {
   component = r.intent.resolveActivity(
       mInitialApplication.getPackageManager());
   r.intent.setComponent(component);
}

if (r.activityInfo.targetActivity != null) {
   component = new ComponentName(r.activityInfo.packageName,
           r.activityInfo.targetActivity);
}

2竞惋、通過(guò)Instrumention的newActivity方法使用類加載器創(chuàng)建Activity對(duì)象

Activity activity = null;
try {
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    StrictMode.incrementExpectedActivityCount(activity.getClass());
    r.intent.setExtrasClassLoader(cl);
    r.intent.prepareToEnterProcess();
    if (r.state != null) {
        r.state.setClassLoader(cl);
    }
} catch (Exception e) {
    if (!mInstrumentation.onException(activity, e)) {
        throw new RuntimeException(
            "Unable to instantiate activity " + component
            + ": " + e.toString(), e);
    }
}

3、通過(guò)LoadedApk的makeApplication方法來(lái)嘗試創(chuàng)建Application對(duì)象
LoadedApk.calss被標(biāo)記為@hide類灰嫉,源碼在sdk/sources/android-22/android/app目錄下

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    // Rewrite the R 'constants' for all library apks.
    SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
            .getAssignedPackageIdentifiers();
    final int N = packageIdentifiers.size();
    for (int i = 0; i < N; i++) {
        final int id = packageIdentifiers.keyAt(i);
        if (id == 0x01 || id == 0x7f) {
            continue;
        }

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
    }

    return app;
}

Application創(chuàng)建完畢后拆宛,系統(tǒng)會(huì)通過(guò)Instrumention的callApplicationOncreate來(lái)調(diào)用Application的onCreate方法

4、創(chuàng)建ContextImpl對(duì)象并通過(guò)Activity發(fā)attach方法來(lái)完成一些重要數(shù)據(jù)的初始化
5讼撒、調(diào)用Activity的onCreate方法

Service的工作過(guò)程

Service的啟動(dòng)過(guò)程

一張圖說(shuō)明Service的啟動(dòng)流程:


這里寫(xiě)圖片描述

handleCreateService方法主要完成如下幾件事:
1浑厚、通過(guò)類加載器創(chuàng)建Service的實(shí)例
2、創(chuàng)建Application對(duì)象并調(diào)用其onCreate方法
3根盒、創(chuàng)建ContextImpl對(duì)象并通過(guò)Service發(fā)attach方法建立二者之間的關(guān)系
4钳幅、調(diào)用Service的onCreate方法并將Service對(duì)象存儲(chǔ)到ActivityThread中的一個(gè)列表中。ActivityThread通過(guò)handleServiceArgs方法調(diào)用Service的onStarCommand方法

Service的綁定過(guò)程

一張圖說(shuō)明Service的綁定過(guò)程:


這里寫(xiě)圖片描述

handleBindService方法主要完成如下幾件事:
1炎滞、根據(jù)Service的token取出Service對(duì)象敢艰,調(diào)用Service的onBind方法
2、通過(guò)ActivityManagerService調(diào)用publishService方法通知客戶端已經(jīng)成功連接Service

BroadcastReceiver的工作過(guò)程

Activity册赛、Service钠导、ContentProvider和BroadcastReceiver的靜態(tài)注冊(cè)都是在應(yīng)用安裝時(shí)由PackageManagerService解析注冊(cè)的。

BroadcastReceiver的注冊(cè)過(guò)程

這里寫(xiě)圖片描述

BroadcastReceiver的發(fā)送和接收過(guò)程

自Android3.1開(kāi)始森瘪,系統(tǒng)為Intent新增了兩個(gè)標(biāo)志牡属,并為所有廣播默認(rèn)添加 FLAG_EXCLUDE_STOPPED_PACKAGES 標(biāo)志,防止無(wú)意間或者在不必要的時(shí)候喚醒已經(jīng)停止的APP扼睬,這個(gè)特性同樣會(huì)影響開(kāi)機(jī)廣播

  • FLAG_INCLUDE_STOPPED_PACKAGES
    表示包含已經(jīng)停止的APP逮栅,這個(gè)時(shí)候廣播會(huì)發(fā)送到已經(jīng)停止的APP
  • FLAG_EXCLUDE_STOPPED_PACKAGES
    表示不包含已經(jīng)停止的APP,這個(gè)時(shí)候廣播不會(huì)發(fā)送給已經(jīng)停止的APP

當(dāng)兩個(gè)標(biāo)志共存時(shí)痰驱,以 FLAG_INCLUDE_STOPPED_PACKAGES 為準(zhǔn)

這里寫(xiě)圖片描述

ContentProvider的工作過(guò)程

當(dāng)ContentProvider所在的進(jìn)程啟動(dòng)時(shí)证芭,ContentProvider會(huì)同時(shí)啟動(dòng)并被發(fā)布到ActivityManagerService中,這個(gè)時(shí)候ContentProvider的onCreate要先于Application的onCreate執(zhí)行担映。

這里寫(xiě)圖片描述

ActivityThread的handleBindApplication方法最終完成Application和ContentProvider的創(chuàng)建废士,步驟如下:

  • 創(chuàng)建ContextImpl和Instrumention
  • 創(chuàng)建Application對(duì)象
  • 啟動(dòng)當(dāng)前進(jìn)程的ContentProvider并調(diào)用其onCreate方法
  • 調(diào)用Application的onCreate方法
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝇完,隨后出現(xiàn)的幾起案子官硝,更是在濱河造成了極大的恐慌矗蕊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氢架,死亡現(xiàn)場(chǎng)離奇詭異傻咖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)岖研,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門卿操,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人孙援,你說(shuō)我怎么就攤上這事害淤。” “怎么了拓售?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵窥摄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我础淤,道長(zhǎng)崭放,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任鸽凶,我火速辦了婚禮币砂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吱瘩。我一直安慰自己道伟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布使碾。 她就那樣靜靜地躺著蜜徽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪票摇。 梳的紋絲不亂的頭發(fā)上拘鞋,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音矢门,去河邊找鬼盆色。 笑死,一個(gè)胖子當(dāng)著我的面吹牛祟剔,可吹牛的內(nèi)容都是我干的隔躲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼物延,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宣旱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起叛薯,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浑吟,失蹤者是張志新(化名)和其女友劉穎笙纤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體组力,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡省容,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燎字。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腥椒。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖轩触,靈堂內(nèi)的尸體忽然破棺而出寞酿,到底是詐尸還是另有隱情家夺,我是刑警寧澤脱柱,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站拉馋,受9級(jí)特大地震影響榨为,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜煌茴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一随闺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔓腐,春花似錦矩乐、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至傀蓉,卻和暖如春欧漱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葬燎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工误甚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谱净。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓窑邦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親壕探。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冈钦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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