Android源碼分析之Activity啟動(dòng)與View繪制流程(一)

我們已經(jīng)掌握了App從創(chuàng)建進(jìn)程到實(shí)例化ActivityThread的過程缰儿,接下來繼續(xù)研究Activity的啟動(dòng)過程。

ActivityThread#handleLaunchActivity說起

Activity的實(shí)例化是在ActivityThread#handleLaunchActivity中完成的,相關(guān)代碼如下:

/frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    // 創(chuàng)建Activity茂缚,并調(diào)用一些方法
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        ...
        // resume
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        ...
    } else {
        ...
    }
}

ActivityonCreateonStart都是在performLaunchActivity方法中完成的,代碼如下:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...

    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        ...
    } catch (Exception e) {
        ...
    }

    try {
        ...

        if (activity != null) {
            // Activity中的Context是在這里創(chuàng)建的
            Context appContext = createBaseContextForActivity(r, activity);
            ...

            // 將一系列字段attach到Activity中
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window);

            ...

            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                // 調(diào)用onCreate
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            ...
            if (!r.activity.mFinished) {
                // 調(diào)用onStart
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    // 保存的狀態(tài)恢復(fù)
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    // 調(diào)用onPostCreate
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                ...
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        ...
    }

    return activity;
}

這里首先執(zhí)行了Activity#attach方法字币,代碼如下:

/frameworks/base/core/java/android/app/Activity.java

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) {
    attachBaseContext(context);

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

    // 創(chuàng)建一個(gè)Window
    mWindow = new PhoneWindow(this, window);
    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);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mReferrer = referrer;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    if (voiceInteractor != null) {
        if (lastNonConfigurationInstances != null) {
            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
        } else {
            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                    Looper.myLooper());
        }
    }

    // 給Window配置WindowManager蕾哟,這是一個(gè)系統(tǒng)服務(wù)
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;
}

這里我們主要關(guān)注mWindow的初始化和WindowManager的配置一忱,mWindow是一個(gè)PhoneWindow的實(shí)例,其中傳給它的參數(shù)window目前為null谭确,它的構(gòu)造方法如下:

/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public PhoneWindow(Context context, Window preservedWindow) {
    this(context);
    // Only main activity windows use decor context, all the other windows depend on whatever
    // context that was given to them.
    mUseDecorContext = true;
    if (preservedWindow != null) {
        // 如果preservedWindow不為空帘营,mDecor是直接獲取的,應(yīng)該和恢復(fù)有關(guān)
        mDecor = (DecorView) preservedWindow.getDecorView();
        ...
    }
    ...
}

可以看到此時(shí)逐哈,只是創(chuàng)建了一個(gè)PhoneWindow芬迄,mDecor還是空的。WindowManager是一個(gè)系統(tǒng)服務(wù)昂秃,通信的方式依然是Binder禀梳,這里不再追蹤,獲取到之后肠骆,通過mWindow.setWindowManager方法完成配置算途,代碼如下:

// /frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ...
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

// /frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow);
}

可見,最終設(shè)置給mWindow對(duì)象的WindowManagerWindowManagerImpl實(shí)例哗戈。

繼續(xù)回到ActivityThread#performLaunchActivity郊艘,接下來調(diào)用的是mInstrumentation.callActivityOnCreate(activity, r.state)方法荷科,代碼如下:

/frameworks/base/core/java/android/app/Instrumentation.java

public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

/frameworks/base/core/java/android/app/Activity.java

final void performCreate(Bundle icicle) {
    restoreHasCurrentPermissionRequest(icicle);
    onCreate(icicle);
    mActivityTransitionState.readState(icicle);
    performCreateCommon();
}

protected void onCreate(@Nullable Bundle savedInstanceState) {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
    if (mLastNonConfigurationInstances != null) {
        mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
    }
    if (mActivityInfo.parentActivityName != null) {
        if (mActionBar == null) {
            mEnableDefaultActionBarUp = true;
        } else {
            mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
        }
    }
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.fragments : null);
    }
    mFragments.dispatchCreate();
    getApplication().dispatchActivityCreated(this, savedInstanceState);
    if (mVoiceInteractor != null) {
        mVoiceInteractor.attachActivity(this);
    }
    mCalled = true;
}

final void performCreateCommon() {
    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mFragments.dispatchActivityCreated();
    mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}

這里處理了Fragment的恢復(fù)工作唯咬,還調(diào)用了Application#dispatchActivityCreated方法以方便記錄Activity的生命周期纱注,包括入場Transition動(dòng)畫也是這時(shí)候處理的。不過我們?cè)?strong>Activity#onCreate中還會(huì)調(diào)用一個(gè)方法:setContentView胆胰,用來加載布局狞贱,否則Activity只有一個(gè)PhoneWindow做不了任何事情,我們需要帶上這個(gè)方法一起分析蜀涨。setContentView會(huì)在上述onCreate執(zhí)行完成后調(diào)用瞎嬉,它的代碼如下:

public void setContentView(@LayoutRes int layoutResID) {
    // 這里的getWindow就是PhoneWindow
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

可見,我們?cè)O(shè)置的布局是加載到了PhoneWindow中的厚柳,相關(guān)代碼如下:

/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public void setContentView(int layoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    // mContentParent是我們?cè)O(shè)置的layout的父布局
    if (mContentParent == null) {
        // 初始化Decor
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        ...
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    ...
}

先看下Decor是如何完成初始化的:

private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        ...
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);

        ...
    }
}

protected DecorView generateDecor(int featureId) {
    // System process doesn't have application context and in that case we need to directly use
    // the context we have. Otherwise we want the application context, so we don't cling to the
    // activity.
    Context context;
    if (mUseDecorContext) {
        Context applicationContext = getContext().getApplicationContext();
        if (applicationContext == null) {
            context = getContext();
        } else {
            context = new DecorContext(applicationContext, getContext().getResources());
            if (mTheme != -1) {
                context.setTheme(mTheme);
            }
        }
    } else {
        context = getContext();
    }
    return new DecorView(context, featureId, this, getAttributes());
}

protected ViewGroup generateLayout(DecorView decor) {
    ...
    // android.R.id.content
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    
    int layoutResource;
    ...

    mDecor.startChanging();
    // 根據(jù)不同的Feature設(shè)置不同的布局文件
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    ...
    return contentParent;
}

至此DecorView創(chuàng)建完畢氧枣,一些初始化工作也完成了,接下來再次回到PhoneWindow#setContentView方法别垮,這里將我們的布局通過mLayoutInflater.inflate(layoutResID, mContentParent)方法添加到了mContentParent中便监。相關(guān)代碼如下:

/frameworks/base/core/java/android/view/LayoutInflater.java

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    ...

    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

解析XML的過程我們就不關(guān)注了,繼續(xù)向下看:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        ...

        try {
            // Look for the root node.
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }
            ...
            if (TAG_MERGE.equals(name)) {
                ...
                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // Temp is the root view that was found in the xml
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                ViewGroup.LayoutParams params = null;

                if (root != null) {
                    if (DEBUG) {
                        System.out.println("Creating params from root: " +
                                root);
                    }
                    // Create layout params that match root, if supplied
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        // Set the layout params for temp if we are not
                        // attaching. (If we are, we use addView, below)
                        temp.setLayoutParams(params);
                    }
                }

                ...

                // Inflate all children under temp against its context.
                rInflateChildren(parser, temp, attrs, true);

                ...

                // We are supposed to attach all the views we found (int temp)
                // to root. Do that now.
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                // Decide whether to return the root that was passed in or the
                // top view found in xml.
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }

        } catch (XmlPullParserException e) {
            ...
        }

        return result;
    }
}

這里我們看到兩個(gè)函數(shù):rInflaterInflateChildren碳想,這兩個(gè)函數(shù)我們要結(jié)合起來看烧董,代碼如下:

final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
        boolean finishInflate) throws XmlPullParserException, IOException {
    rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}

void rInflate(XmlPullParser parser, View parent, Context context,
        AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

    final int depth = parser.getDepth();
    int type;

    while (((type = parser.next()) != XmlPullParser.END_TAG ||
            parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {

        if (type != XmlPullParser.START_TAG) {
            continue;
        }

        final String name = parser.getName();
        
        if (TAG_REQUEST_FOCUS.equals(name)) {
            parseRequestFocus(parser, parent);
        } else if (TAG_TAG.equals(name)) {
            parseViewTag(parser, parent, attrs);
        } else if (TAG_INCLUDE.equals(name)) {
            if (parser.getDepth() == 0) {
                throw new InflateException("<include /> cannot be the root element");
            }
            parseInclude(parser, context, parent, attrs);
        } else if (TAG_MERGE.equals(name)) {
            throw new InflateException("<merge /> must be the root element");
        } else {
            final View view = createViewFromTag(parent, name, context, attrs);
            final ViewGroup viewGroup = (ViewGroup) parent;
            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
            rInflateChildren(parser, view, attrs, true);
            viewGroup.addView(view, params);
        }
    }

    if (finishInflate) {
        parent.onFinishInflate();
    }
}

可以看到,這兩個(gè)函數(shù)胧奔,在循環(huán)地互相調(diào)用逊移,直到所有的View都解析完畢,最后調(diào)用到parent.onFinishInflate()方法龙填,完成inflate過程胳泉。

經(jīng)過以上步驟后,Activity就創(chuàng)建完畢了岩遗,于此同時(shí)DecorView和我們的布局文件都初始化完成了胶背,但是DecorView還沒有添加到Window中,不能進(jìn)行顯示喘先。我們?cè)俅位氐?strong>ActivityThread#performLaunchActivity中钳吟,接下來就該是activity.performStart()了,代碼如下:

/frameworks/base/core/java/android/app/Activity.java

final void performStart() {
    mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    mFragments.noteStateNotSaved();
    mCalled = false;
    mFragments.execPendingActions();
    mInstrumentation.callActivityOnStart(this);
    if (!mCalled) {
        throw new SuperNotCalledException(
            "Activity " + mComponent.toShortString() +
            " did not call through to super.onStart()");
    }
    mFragments.dispatchStart();
    mFragments.reportLoaderStart();
    ...
}

這里看到了一點(diǎn)FragmentActivity生命周期的問題窘拯,我們以后再來研究它红且。Instrumentation#callActivityOnStartActivity#onStart并沒有做什么事,這里還是粘貼下它的代碼:

// /frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnStart(Activity activity) {
    activity.onStart();
}

// /frameworks/base/core/java/android/app/Activity.java
protected void onStart() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
    mCalled = true;

    mFragments.doLoaderStart();

    getApplication().dispatchActivityStarted(this);
}

繼續(xù)回到ActivityThread#performLaunchActivity涤姊,接下來調(diào)用了ActivityThread#handleResumeActivity方法暇番,代碼如下:

/frameworks/base/core/java/android/app/ActivityThread.java

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ...

    // TODO Push resumeArgs into the activity for consideration
    r = performResumeActivity(token, clearHide, reason);

    if (r != null) {
        final Activity a = r.activity;

        ...

        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        boolean willBeVisible = !a.mStartedActivity;
        ...
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            // 先將Decor不可見
            decor.setVisibility(View.INVISIBLE);
            ...
            // Window已經(jīng)恢復(fù),之前保持的狀態(tài)要改變
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                ...
            }
            if (a.mVisibleFromClient && !a.mWindowAdded) {
                a.mWindowAdded = true;
                // 把Decor加載到Window中
                wm.addView(decor, l);
            }

        // If the window has already been added, but during resume
        // we started another activity, then don't yet make the
        // window visible.
        } else if (!willBeVisible) {
            ...
        }

        // Get rid of anything left hanging around.
        cleanUpPendingRemoveWindows(r, false /* force */);

        // The window is now visible if it has been added, we are not
        // simply finishing, and we are not starting another activity.
        if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
            ...
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
                // 可以可見了
                r.activity.makeVisible();
            }
        }

        ...

        // Tell the activity manager we have resumed.
        if (reallyResume) {
            try {
                ActivityManagerNative.getDefault().activityResumed(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }

    } else {
        ...
    }
}

這里處理了很多工作思喊,首先通過performResumeActivity調(diào)用Activity#onResume壁酬,使得Activity進(jìn)入onResume狀態(tài),然后將DecorView添加到Window中并顯示出來。先看下performResumeActivity的實(shí)現(xiàn):

public final ActivityClientRecord performResumeActivity(IBinder token,
        boolean clearHide, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    if (localLOGV) Slog.v(TAG, "Performing resume of " + r
            + " finished=" + r.activity.mFinished);
    if (r != null && !r.activity.mFinished) {
        if (clearHide) {
            r.hideForNow = false;
            r.activity.mStartedActivity = false;
        }
        try {
            ...
            r.activity.performResume();

            ...
        } catch (Exception e) {
            ...
        }
    }
    return r;
}

繼續(xù)跟蹤舆乔,到了Activity#performResume方法岳服,代碼如下:

final void performResume() {
    performRestart();

    ...
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);
    ...

    // Now really resume, and install the current status bar and menu.
    mCalled = false;

    mFragments.dispatchResume();
    mFragments.execPendingActions();

    onPostResume();
    ...
}

final void performRestart() {
    ...
    // Activity是Stop時(shí)才會(huì)執(zhí)行以下代碼
    if (mStopped) {
        mStopped = false;

        ...

        mCalled = false;
        mInstrumentation.callActivityOnRestart(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onRestart()");
        }
        // onRestart之后立即執(zhí)行onStart
        performStart();
    }
}

然后通過Instrumentation#callActivityOnResume再調(diào)用Activity#onResume方法,之后Activity就進(jìn)入了onResume狀態(tài)希俩。最后吊宋,當(dāng)Activity確實(shí)Resume之后,還通知了ActivityManagerService以進(jìn)行一些其他操作颜武。

接下來璃搜,我們看下Window加載DecorView的過程,它是通過設(shè)置給WindowWindowManager完成的鳞上,也就是WindowManagerImpl對(duì)象这吻,相關(guān)代碼如下:

/frameworks/base/core/java/android/view/WindowManagerImpl.java

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

可以看到DecorView添加到了一個(gè)全局的WindowManagerGlobal中,相關(guān)代碼如下:

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ...
    synchronized (mLock) {
        ...

        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    // do this last because it fires off messages to start doing things
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        ...
    }
}

WindowManagerGlobal中保存了一系列的ViewRootImpl實(shí)例篙议,我們每增加一個(gè)布局橘原,就會(huì)新建一個(gè)ViewRootImpl對(duì)象,接下來看它的setView方法涡上,代碼如下:

/frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        // if確保了只有一個(gè)View
        if (mView == null) {
            mView = view;

            ...

            // Schedule the first layout -before- adding to the window
            // manager, to make sure we do the relayout before receiving
            // any other events from the system.
            requestLayout();
            ...
            try {
                ...
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
            } catch (RemoteException e) {
                ...
            }

            ...

            view.assignParent(this);
            ...
        }
    }
}

這里首先調(diào)用了requestLayout方法渲染頁面趾断,然后通過mWindowSession.addToDisplay將頁面添加到WindowManagerService中。我們先看前一個(gè)方法吩愧,代碼如下:

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

在這里看到checkThread不禁眼前一亮芋酌,它的實(shí)現(xiàn)如下:

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

這就是說,直到onResume之后雁佳,Activity才會(huì)檢查是否在非UI線程更新UI脐帝。繼續(xù)看其他部分,代碼如下:

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

這里使用了MessageQueue#postSyncBarrier方法糖权,這個(gè)方式稱為同步屏障堵腹,可以通過此發(fā)送一個(gè)異步消息,這個(gè)消息將會(huì)優(yōu)先被執(zhí)行星澳,具體的解釋可以看我的文章:Android源碼分析之Handler疚顷。接下來部分代碼會(huì)跳轉(zhuǎn)至Native完成,最終會(huì)執(zhí)行到mTraversalRunnable這個(gè)回調(diào)里禁偎,代碼如下:

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

也就是說系統(tǒng)會(huì)盡快執(zhí)行TraversalRunnable#run方法腿堤,代碼如下:

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        ...
        performTraversals();
        ...
    }
}

首先會(huì)解除屏障,然后執(zhí)行performTraversals方法如暖,從這里開始笆檀,View將會(huì)進(jìn)行measurelayout盒至、draw等過程酗洒。限于篇幅士修,下一篇文章繼續(xù)分析。

上一篇:Android源碼分析之App啟動(dòng)流程(二)

下一篇:Android源碼分析之Activity啟動(dòng)與View繪制流程(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末樱衷,一起剝皮案震驚了整個(gè)濱河市棋嘲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箫老,老刑警劉巖封字,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黔州,死亡現(xiàn)場離奇詭異耍鬓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)流妻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門牲蜀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绅这,你說我怎么就攤上這事涣达。” “怎么了证薇?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵度苔,是天一觀的道長。 經(jīng)常有香客問我浑度,道長寇窑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任箩张,我火速辦了婚禮甩骏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘先慷。我一直安慰自己饮笛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布论熙。 她就那樣靜靜地躺著福青,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脓诡。 梳的紋絲不亂的頭發(fā)上素跺,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音誉券,去河邊找鬼指厌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛踊跟,可吹牛的內(nèi)容都是我干的踩验。 我是一名探鬼主播鸥诽,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼箕憾!你這毒婦竟也來了牡借?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤袭异,失蹤者是張志新(化名)和其女友劉穎钠龙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體御铃,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碴里,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了上真。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咬腋。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖睡互,靈堂內(nèi)的尸體忽然破棺而出根竿,到底是詐尸還是另有隱情,我是刑警寧澤就珠,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布寇壳,位于F島的核電站,受9級(jí)特大地震影響妻怎,放射性物質(zhì)發(fā)生泄漏壳炎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一蹂季、第九天 我趴在偏房一處隱蔽的房頂上張望冕广。 院中可真熱鬧,春花似錦偿洁、人聲如沸撒汉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睬辐。三九已至,卻和暖如春宾肺,著一層夾襖步出監(jiān)牢的瞬間溯饵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工锨用, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丰刊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓增拥,卻偏偏與公主長得像啄巧,于是被迫代替她去往敵國和親寻歧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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