android之View绘制到窗口上的过程

ActivityThread#handleResumeActivity方法

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,boolean reallyResume) {……ActivityClientRecord r = performResumeActivity(token, clearHide);……if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();//前面分析过,这个是Window对象所维护的装饰窗口,最顶层的窗口decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();//获取WindowManager,继承自ViewManager,不可实例化,,是个接口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);// 通过WindowManager添加到窗口}……}

可以看到最顶层的装饰窗口在activity resume的时候通过windowManager#addView方法添加。

WindowManagerImpl# addView

public void addView(View view, ViewGroup.LayoutParams params) {mGlobal.addView(view, params, mDisplay, mParentWindow);}public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {ViewRootImpl root;View panelParentView = null;……root = new ViewRootImpl(view.getContext(), display); // 创建一个ViewRoot对象view.setLayoutParams(wparams);if (mViews == null) {index = 1;mViews = new View[1];mRoots = new ViewRootImpl[1];mParams = new WindowManager.LayoutParams[1];} else {index = mViews.length + 1;Object[] old = mViews;mViews = new View[index];System.arraycopy(old, 0, mViews, 0, index-1);old = mRoots;mRoots = new ViewRootImpl[index];System.arraycopy(old, 0, mRoots, 0, index-1);old = mParams;mParams = new WindowManager.LayoutParams[index];System.arraycopy(old, 0, mParams, 0, index-1);}index–;mViews[index] = view;mRoots[index] = root;// 将view和ViewRootImp关联起来 ViewRootImp是链接View和WindowManagerService的桥梁mParams[index] = wparams;}try {root.setView(view, wparams, panelParentView);// 调用ViewRoot的setView方法} ……}

setView:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { requestLayout(); // 请求UI开始绘制重新绘制View树……try {mOrigWindowType = mWindowAttributes.type;mAttachInfo.mRecomputeGlobalAttributes = true;collectViewAttributes();// 通知WindowManagerService添加一个窗口 会调用到addWindow方法res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mInputChannel);}}

两种情况会导致调用到requestLayout,改变视图显示属性,比如setVisibility,是直接或者间接调用该函数。

@Overridepublic void requestLayout() {checkThread();// 本次调用是否是在UI线程调用的。mLayoutRequested = true;scheduleTraversals();}void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;mTraversalBarrier = mHandler.getLooper().postSyncBarrier();//分发一个异步消息,处理函数中调用performTraversals()对View进行重新遍历。mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// mTraversalRunnable是一个Runnable对象scheduleConsumeBatchedInput();}}final TraversalRunnable mTraversalRunnable = new TraversalRunnable();final class TraversalRunnable implements Runnable {@Overridepublic void run() {doTraversal();//执行doTraversal()}}void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);……try {performTraversals();} finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);}……}}

View树遍历的核心函数 measure—layout–draw

private void performTraversals() {……// Ask host how big it wants to beperformMeasure(childWidthMeasureSpec, childHeightMeasureSpec);……performLayout();……performDraw();……mIsInTraversal = false;}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);}}

mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);就执行到了熟悉onMeasure(childWidthMeasureSpec,childHeightMeasureSpec);里面。

偶尔为街头独特的风景驻足,

android之View绘制到窗口上的过程

相关文章:

你感兴趣的文章:

标签云: