Activity是什么時候顯示出來的?

概要

在Android開發(fā)中,Activity可謂是最重要之一的組件了。分析和熟悉Activity的啟動流程,可幫助認(rèn)識整個Android系統(tǒng)全貌。這里主要分析基于Android7.0從startActivity到Activity頁面顯示這一過程。

1.涉及主要類:

android.app.Instrumentation.java 
android.app.ActivityThread.java
android.app.ActivityManager.java
com.android.server.am.ActivityManagerService.java
com.android.internal.policy.PhoneWindon.java
com.android.internal.policy.DecorView.java
android.view.WindowManage.java
com.android.server.wm.WindowManagerService.java

2.流程圖:


avtivity啟動流程圖.png

具體流程

1.Activity.startActivityForResult()
/**
 * @hide
 */
@Override
public void startActivityForResult(
        String who, Intent intent, int requestCode, @Nullable Bundle options) {
    ...
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, who,
            intent, requestCode, options);
  ...
    }
    cancelInputsAndStartExitTransition(options);
}

首先我們看看這個mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, who,intent, requestCode, options)這個方法。其中第二個參數(shù)是ActivityThread類中的內(nèi)部類ApplicationThread,這個是IBinder的代理類,用戶接收ActivityMangageService的消息。

2.Instrumentation.execStartActivity()
 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
      ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

這個方法主要通過IPC方式發(fā)送消息給AMS(指ActivityManageService.java(下同)),從而調(diào)用startActivity(),這里就涉及到AMS服務(wù)了,在這過程中會進(jìn)行一系列的準(zhǔn)備,其中保存判斷被啟動的的Activity所在的進(jìn)程是否和當(dāng)前Activity所在的進(jìn)程一致,若不一致則會從zygote進(jìn)程fork一個進(jìn)程;還有比如Activity的啟動方式的判斷等。最終會通過Binder IPC調(diào)用ActivityThread.ApplicationThread中的scheduleLaunchActivity()方法

3.ActivityThread.ApplicationThread. scheduleLaunchActivity()

在這一步驟中會通過sendMessage(H.LAUNCH_ACTIVITY, r)發(fā)送消息給ActivityThread.H,從而調(diào)用handleLaunchActivity()方法;

4.ActivityThread.handleLaunchActivity()
  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    //省略部分代碼
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
     //省略部分代碼
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
      //省略部分代碼
      }
}

這里主要看performLaunchActivity()這個方法,這個里面會創(chuàng)建Activity的實例,然后在調(diào)用Activity.attach()方法,之后調(diào)用Activity的一系列生命周期方法。

5.Activity.attach()
    final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    //省略部分代碼
}

這個方法參數(shù)比較多,我們主要看下對應(yīng)的Window的創(chuàng)建:通過代碼我們可以看到只要調(diào)用attach方法就會創(chuàng)建一個對應(yīng)的window,也就是說一個Activity對應(yīng)一個window(window只有個實現(xiàn)類就是PhoneWindow)。PhoneWindow創(chuàng)建的同時又會創(chuàng)建DecorView(相當(dāng)于是Activity的rootView)。

    public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks 

DecorView繼承與FrameLayout,查看PhoneWindow.java源碼你會發(fā)現(xiàn)會DecorView添加兩個子View:R.id.title和com.android.internal.R.id.content。到這里就可以知道Activity和Window的關(guān)系了:


activity和window關(guān)系圖.png
6.Activity.makeVisible()
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

執(zhí)行完attach之后緊接著會調(diào)用Activity中的相關(guān)生命周期方法onCreate()、onStart()和onResume()方法。之后就會執(zhí)行上面的makeVisible()方法,這里才是真正的開始繪制顯示Activity視圖。在這個方法中會調(diào)用windowManage添加window,最終會通過ViewRootImpl.java這個類的setView(),然后在通過Binder IPC和WindowManageService通信最終完成window的添加。
這里有個問題:當(dāng)我們每次去更新UI的時候都是通過ViewRootImpl去執(zhí)行更新以及檢查當(dāng)前執(zhí)行更新的線程。而ViewRootImpl的創(chuàng)建就是在執(zhí)行wm.addView()的時候創(chuàng)建的。所以在ViewRootImpl沒有創(chuàng)建之前是不會對線程進(jìn)程檢查及更新繪制UI的。

總結(jié)

通過對Activity的啟動過程及視圖的呈現(xiàn)分析,我們可以總結(jié)如下:

1、通過Binder IPC的方式和AMS通信完成Activity創(chuàng)建前的一系列準(zhǔn)備。若要啟動的這個Activity所在的進(jìn)程沒有啟動,那么AMS會通過Socket發(fā)送消息給Zygote,Zygote會fork出應(yīng)用程序進(jìn)程,并且通過反射創(chuàng)建這個應(yīng)用程序的ActivityThread,并且調(diào)用ActivityThread的main方法,此時這個應(yīng)用程序就啟動了;

2、在AMS完成準(zhǔn)備工作之后又以IPC的方式發(fā)送lunchActivity消息,ActivityThread.ApplicationThreah 收到消息之后,又通過handler機(jī)制發(fā)送LAUNCH_ACTIVITY消息給ActivityThread.H;

3、之后通過Instrumentation.newActivity()完成Activity的創(chuàng)建;

( Activity activity = (Activity)clazz.newInstance())

4、在創(chuàng)建完Activity實例之后會調(diào)用Activity.acctch()方法完成window和DecorView的創(chuàng)建,最終通過WindowManage.addView()完成對window的添加。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Zygote是什么?有什么作用? Android系統(tǒng)底層基于Linux Kernel, 當(dāng)Kernel啟動過程會創(chuàng)...
    Mr槑閱讀 2,918評論 4 18
  • 前言 Launcher啟動app launcher就是android桌面應(yīng)用程序。也是操作系統(tǒng)啟動有第一個app。...
    第八區(qū)閱讀 1,153評論 0 2
  • 還真是的。養(yǎng)它足足考驗了我的耐心,就連這幾天做夢,都會夢見它煤球一樣的臉,圍著我的腳,繞來繞去。 十幾天了,就算是...
    寧黛閱讀 203評論 0 1
  • 長城是由傳奇影業(yè)、環(huán)球影業(yè)、中影、樂視影業(yè)等影業(yè)公司聯(lián)合出品。據(jù)透露,傳奇影業(yè)負(fù)責(zé)劇本開發(fā)、制片、投資;環(huán)球影業(yè)負(fù)...
    北城巷陌閱讀 909評論 2 2
  • 文||胡思入夢菲 我想有所房子,不是面朝大海,卻是春暖花開。房子不需要很大,也不用建在繁華的都市。 它可以在寧靜的...
    丁漁閱讀 366評論 7 8

友情鏈接更多精彩內(nèi)容