Activity工作過(guò)程(2)-《Andoid開發(fā)藝術(shù)探索》《深入解析Android5.0系統(tǒng)》結(jié)合分析

先看這張圖吧:

ScreenClip.png

在這些類的調(diào)用過(guò)程中荡灾,尤其是在ActivityStack和ActivityStackStack這兩個(gè)類中都在頻繁的操控Activity的生命周期調(diào)度筷黔,
這個(gè)是Activity onCreate()的調(diào)度方法:

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
                    results, newIntents, !andResume, mService.isNextTransitionForward(),
                    profilerInfo);

這個(gè)是 Activity onResume( ) 的調(diào)度方法:

next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                    mService.isNextTransitionForward(), resumeAnimOptions);

這里的app.thread到底是何方神圣鞠眉,為什么不直接操作Activity而是要通過(guò)這樣一個(gè)app.Thread(app.Thread并不是Thread)?
先認(rèn)識(shí)下這個(gè)Thread
/**

  • System private API for communicating with the application. This is given to
  • the activity manager by an application when it starts up, for the activity
  • manager to tell the application about things it needs to do.
  • {@hide}
    */
    public interface IApplicationThread extends IInterface
    其內(nèi)部包含了大量啟動(dòng),停止Activity的接口還包含了啟動(dòng)和停止服務(wù)的接口從命名可以看出路捧,IApplicationThread 這個(gè)Binder接口的實(shí)現(xiàn)者完成了大量的Activity以及Service啟動(dòng)/停止相關(guān)的功能淹真。
    那我們就來(lái)看看IApplicationThread 的實(shí)現(xiàn)類:
    public abstract class ApplicationThreadNative extends Binder implements IApplicationThread
    雖然這個(gè)是抽象類讶迁,但是其中也做了相當(dāng)多的操作如:
class ApplicationThreadProxy implements IApplicationThread {
    ···
public final void scheduleResumeActivity(IBinder token, int procState, boolean isForward,
            Bundle resumeArgs)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeStrongBinder(token);
        data.writeInt(procState);
        data.writeInt(isForward ? 1 : 0);
        data.writeBundle(resumeArgs);
        mRemote.transact(SCHEDULE_RESUME_ACTIVITY_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    ···
 }

沒錯(cuò),這就是系統(tǒng)為AIDL文件自動(dòng)生成的代理類核蘸。

ActivityThread有個(gè)內(nèi)部類ApplicationThread 巍糯,
private class ApplicationThread extends ApplicationThreadNative

最終回到了ApplicationThread 的 scheduleLaunchActivity()

// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                IVoiceInteractor voiceInteractor, int procState, Bundle state,
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();
                ···
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

沒啥難度,重點(diǎn)在最后一句客扎,發(fā)送一個(gè)啟動(dòng)Activity的消息給ActivityThread內(nèi)部的Handler祟峦;
哪里有handler?額徙鱼,它有個(gè)大方且?guī)洑獾拿郑?br> private class H extends Handler
呵呵 宅楞, 我方了
看看我們的H干了點(diǎn)啥:

 case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } 
   break;

這里只是等待處理完成后關(guān)閉trace,算是完成了一次進(jìn)程間通信袱吆,有讀取有回寫厌衙,相當(dāng)完美。
回到重點(diǎn):

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ···
        //開啟activity的create之旅
        Activity a = performLaunchActivity(r, customIntent);
        //啟動(dòng)完畢接下來(lái)進(jìn)入onResume()
        if (a != null) {
        ···
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);

        }
    }

在這之前其實(shí)有個(gè)小小的疑問(wèn)绞绒,這時(shí)候Handler為什么可以調(diào)用婶希?(雖然我們是從startActivity開始,但是如果應(yīng)用剛剛開始蓬衡,這個(gè)ActivityThread一定會(huì)在App啟動(dòng)的時(shí)候悄悄搞點(diǎn)事情)而且拉風(fēng)的H竟然還掌控著Activity的生命周期喻杈,這個(gè)神奇的UIThread到底是什么時(shí)候,被誰(shuí)創(chuàng)建出來(lái)的呢狰晚?
答案在ApplicationInit()里:
ApplicationInit()除了設(shè)置虛擬機(jī)的兩個(gè)參數(shù)外筒饰,最重要的是調(diào)用了invokeStaticMain(args.startClass,args.startArgs),調(diào)用的參數(shù)args.startClass是通過(guò)socket傳入的壁晒,通常是“android.app.ActivityThread”這樣將會(huì)調(diào)用ActivityThread的main()方法瓷们。但是invokeStaticMain()并不是直接調(diào)用main()方法,而是拋出了一個(gè)Exception:

throw new ZygoteInit.MethodAndArgsCaller(m,argv);

在 ZygoteInit的mian()方法中會(huì)catch這個(gè)Exception:

catch (MethodAndArgsCaller caller){
    caller.run();
}

這里為什么要先拋出一個(gè)Exception是因?yàn)閺腪ygoteInit調(diào)用開始到最終進(jìn)入invokeStaticMain()系統(tǒng)的棧里面已經(jīng)累積了不少調(diào)用幀,調(diào)用ActivityThread的mian()函數(shù)不會(huì)返回谬晕,為了能清除前面的調(diào)用棧幀式镐,給新運(yùn)行的應(yīng)用一個(gè)干凈的環(huán)境,才使用了throw Exception的方式固蚤。

 public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
//設(shè)置進(jìn)程名稱
        Process.setArgV0("<pre-initialized>");
//初始化Looper
        Looper.prepareMainLooper();
//創(chuàng)建ActivityThread 
        ActivityThread thread = new ActivityThread();
        //通過(guò)False主動(dòng)調(diào)用attach
        thread.attach(false);

        if (sMainThreadHandler == null) {//保存主線程的Handler
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();//初始化AsyncTask類

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

看看ActivityThread 的 attach()都綁定了什么 :

private void attach(boolean system) {
       ···
        if (!system) {
           ···
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            //把ApplicationThread對(duì)象放到RuntimeInit中
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
            //把ApplicationThread傳入AMS并調(diào)用AMS的attachApplication()
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
           ···
        } else {
            ···
        }

     ···
    }

竟然推著ActivityManagerService也跟著動(dòng)了起來(lái):

attachApplication( ) -> attachApplicationLocked( ) ->ApplicationThread.bindApplication( )
這里bindApplication()會(huì)發(fā)送消息BIND_APPLICATION

private void handleBindApplication(AppBindData data)

這里主要作用就是創(chuàng)建應(yīng)用框架中的各種對(duì)象:
InstrumentationInfo
Instrumentation
ApplicationInfo
Application
LoadedApk
ContextImpl
···

->mStackSupervisor.attachApplicationLocked()->mStackSupervisor.realSrartActivityLocked( )
這個(gè)方法里做了判斷娘汞,如果進(jìn)程沒有啟動(dòng)則啟動(dòng)進(jìn)程,如果進(jìn)程啟動(dòng)了則調(diào)用Activity的onResume( )
最后用圖說(shuō)話(后來(lái)補(bǔ)上的):

QQ圖片20170329233031.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夕玩,一起剝皮案震驚了整個(gè)濱河市你弦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌燎孟,老刑警劉巖禽作,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異揩页,居然都是意外死亡旷偿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門爆侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)萍程,“玉大人,你說(shuō)我怎么就攤上這事兔仰∶8海” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵乎赴,是天一觀的道長(zhǎng)忍法。 經(jīng)常有香客問(wèn)我,道長(zhǎng)榕吼,這世上最難降的妖魔是什么饿序? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮羹蚣,結(jié)果婚禮上原探,老公的妹妹穿的比我還像新娘。我一直安慰自己度宦,他們只是感情好踢匣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布告匠。 她就那樣靜靜地躺著戈抄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪后专。 梳的紋絲不亂的頭發(fā)上划鸽,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼裸诽。 笑死嫂用,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丈冬。 我是一名探鬼主播嘱函,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼埂蕊!你這毒婦竟也來(lái)了往弓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蓄氧,失蹤者是張志新(化名)和其女友劉穎函似,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喉童,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡撇寞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堂氯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔑担。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咽白,靈堂內(nèi)的尸體忽然破棺而出钟沛,到底是詐尸還是另有隱情,我是刑警寧澤局扶,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布恨统,位于F島的核電站,受9級(jí)特大地震影響三妈,放射性物質(zhì)發(fā)生泄漏畜埋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一畴蒲、第九天 我趴在偏房一處隱蔽的房頂上張望悠鞍。 院中可真熱鬧,春花似錦模燥、人聲如沸咖祭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)么翰。三九已至,卻和暖如春辽旋,著一層夾襖步出監(jiān)牢的瞬間浩嫌,已是汗流浹背檐迟。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留码耐,地道東北人追迟。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像骚腥,于是被迫代替她去往敵國(guó)和親敦间。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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