Android GUI之View繪製流程

  在上篇文章中,咱們經過跟蹤源碼,咱們瞭解了Activity、Window、DecorView以及View之間的關係(查看文章:http://www.cnblogs.com/jerehedu/p/4607599.html#gui)。那麼整個Activity的界面究竟是如何繪製出來的呢?既然DecorView做爲Activity的頂層界面視圖,那麼整個界面的繪製工做應該從它開始,下面咱們繼續跟蹤源碼,看看是否是這樣的。html

  Activity在啓動過程當中會調用主線程ActivityThread中的方法performLaunchActivity和handleResumeActivity。在方法handleResumeActivity中會將建立的DecorView和WindowManagerImpl對象關聯起來,關鍵源碼部分以下:web

public final class ActivityThread {
   ……
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
      ……
            if (r.window == null && !a.mFinished && willBeVisible) {
                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;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

            } 
……
    }
}

  WindowManagerImpl關鍵代碼:canvas

    public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
……
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
      mGlobal.addView(view, params, mDisplay, mParentWindow);
}
……
}

  WindowManagerGlobal關鍵代碼:app

public final class WindowManagerGlobal {
    ……
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
           ……
        ViewRootImpl root;
        View panelParentView = null;
……
        root.setView(view, wparams, panelParentView);
           ……
    }
}

  根據源碼調用關係,可得下圖:ide

  從圖中,咱們能夠看出在ActivityThread中生成的DecorView通過WindowManagerImpl、WindowManagerGlobal,最終調用了ViewRootImpl中的setView方法,將DecorView設置賦值給了ViewRootImpl中的mView屬性。經過追蹤ViewRootImpl咱們發現最終調用了performTraversals方法,該方法關鍵代碼以下:ui

private void performTraversals() {
        // cache mView since it is used so much below...
        final View host = mView;
        ……
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        ……
        performLayout(lp, desiredWindowWidth, desiredWindowHeight);
        ……
        performDraw();
        ……
}

  從上述源碼中咱們能夠看出,performTraversals實際上依次調用了三個關鍵的方法,分別是performMeasure,performLayout、performDraw。this

  一、方法performMeasure,內部實際上調用了mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);不要忘了此處的mView正是咱們傳遞進來的DecorView,該方法用於測量View的大小。關鍵源碼以下:spa

        private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

  二、方法performLayout,內部實際上調用了host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());該方法用於肯定視圖的位置。關鍵源碼以下:線程

    private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;

        final View host = mView;
        ……
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

            mInLayout = false;
            int numViewsRequestingLayout = mLayoutRequesters.size();
            if (numViewsRequestingLayout > 0) {
              ……
                if (validLayoutRequesters != null) {
                    // Set this flag to indicate that any further requests are happening during
                   ……
                    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

                   ……                   
 }
                }

            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mInLayout = false;
    }

  三、方法performDraw,用於繪製視圖,追蹤源碼發現,最終調用了mView.draw(canvas)方法,用於繪製。code

  通過上述過程基本上能夠肯定View的繪製流程,流程圖具體以下:

 

  疑問諮詢或技術交流,請加入官方QQ羣:JRedu技術交流 (452379712)

 

做者: 傑瑞教育
出處: http://www.cnblogs.com/jerehedu/ 
本文版權歸煙臺傑瑞教育科技有限公司和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索