標籤:
在上篇文章中,我們通過跟蹤源碼,我們瞭解了Activity、Window、DecorView以及View之間的關係(查看文章:http://blog.csdn.net/jerehedu/article/details/47021541)。那麼整個Activity的介面到底是如何繪製出來的呢?既然DecorView作為Activity的頂層介面視圖,那麼整個介面的繪製工作應該從它開始,下面我們繼續跟蹤源碼,看看是不是這樣的。
Activity在啟動過程中會調用主線程ActivityThread中的方法performLaunchActivity和handleResumeActivity。在方法handleResumeActivity中會將建立的DecorView和WindowManagerImpl對象關聯起來,關鍵源碼部分如下:
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關鍵代碼:
public final class WindowManagerImpl implements WindowManager {private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();……@Overridepublic void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow);}……}
WindowManagerGlobal關鍵代碼:
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); …… }}
根據源碼調用關係,可得:
,我們可以看出在ActivityThread中產生的DecorView經過WindowManagerImpl、WindowManagerGlobal,最終調用了ViewRootImpl中的setView方法,將DecorView設定賦值給了ViewRootImpl中的mView屬性。通過追蹤ViewRootImpl我們發現最終調用了performTraversals方法,該方法關鍵代碼如下:
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。
1、方法performMeasure,內部實際上調用了mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);不要忘了此處的mView正是我們傳遞進來的DecorView,該方法用於測量View的大小。關鍵源碼如下:
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); } }
2、方法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; }
3、方法performDraw,用於繪製視圖,追蹤源碼發現,最終調用了mView.draw(canvas)方法,用於繪製。
經過上述過程基本上可以確定View的繪製流程,流程圖具體如下:
疑問諮詢或技術交流,請加入官方QQ群: (452379712)
傑瑞教育
出處:http://blog.csdn.net/jerehedu/
本文著作權歸煙台傑瑞教育科技有限公司和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android GUI之View繪製流程