在上篇文章中,咱們經過跟蹤源碼,咱們瞭解了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羣: (452379712)