Android View 工作原理

本文從Activity 創建view,到View的繪制全過程,最終呈現在Activity做一個比較全面的梳理。

1. View在Activity上創建

這里要提到有關Activiy、Window、WindowManager等的相關知識。
ActivityThread 的performLaunchActivity是啟動一個Activity的入口,此方法會創建一個Activity。

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            //1. 通過反射創建一個acitiviy
            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) {
            ...
        }

        try {
               ...
              //2. 創建window 對象
                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);
                ...
                //3. 調用ActivityOncreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
        return activity;
    }

在Activity的attach中創建相應的PhoneWindow對象,并設置回調(詳見PhoneWindow中Callback接口),此時Activity持有該Window對象

  final void attach(Context context, ActivityThread aThread,
            Instrumentation instr,...) {
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
  }

當我們在Activity的setContentView方法調用了Window的setContentView ,

public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

實際上調用了Window的setContentView

public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            //1. 構建Decor
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            // 2. 將布局inflate到mContentParent上
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            //3. 回調給Activity
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

mContentParent相當于是DecorView的一部分,用來繪制content的部分

 private void installDecor() {
      ...
      mContentParent = generateLayout(mDecor);
      ...
}
protected ViewGroup generateLayout(DecorView decor) {
      //其中ID_ANDROID_CONTENT 即com.android.internal.R.id.content
       ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
       return contentParent
}

至此View被添加到頂級View, DecorView上,并顯示在Activity的Window上了。

在ActivityThread的handleResumeActivity接口里:

r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
               ...
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // ViewManager的實現ViewManagerImpl 調用WindowManagerGlobal(WindowManager的實現)將DecorView添加到
                    wm.addView(decor, l);
                }

WindowManagerGlobal的addview會

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

其實ViewRootImpl的mView就是頂級View:Decoview 。
至此View被添加DecorView上并進入繪制流程。

2. View的繪制流程

在調用ViewRootImpl的setView中會執行其requestLayout方法


    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            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.
            //在添加到windowMaganer之前首次執行layout
            requestLayout();
        }
    }

requestLayout會依次調用scheduleTraversals->doTraversal->performTraversals并最終進入繪制流程。
performTraversals會依次調用performMeasure,performDraw, performLayout,并相應的執行mView(DecorView)的measure,draw, layout,
到此view的繪制告一段落了。后面會繼續講到一些view繪制的詳細內容

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容