赞
踩
ViewRootImpl 是 View 的最高层级,是所有 View 的根。ViewRootImpl 实现了 View 和 WindowManager 之间所需要的协议。ViewRootImpl 的创建过程是从 WindowManagerImpl
中开始的。View 的测量,布局,绘制以及上屏,都是从 ViewRootImpl 中开始的。
我们通过一张图来认识一下它:
Window
我们知道界面中所有的元素都是由 View 构成的,View 是依附于 Window 上面的。Window 只是一个抽象概念,把界面抽象成一个 窗口,也可以抽象成一个 View。
ViewManange
一个接口,内部定义了三个方法,用来对 VIew 的添加,更新和删除。
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
WindowManager
也是一个接口,继承自 ViewManager,在应用程序中,通过 WindowManager 来管理 Window,将 View 附加到 Window 上。他有一个实现类 WindowManagerImpl
。
WindowManagerImpl
WindowManager
的实现类,WindowManagerImpl
中的内部方法实现都是通过代理类 WindowManagerGlobal
来完成。
WindowManagerGlobal
WindowManagerGlobal
是一个单例,也就是说一个进程中只有一个 WindowManagerGlobal
对象,他服务与所有页面的 View。
ViewParent
一个接口,定义了将成为 View 父级类的职责。
ViewRootImpl
视图层次结构的顶部。一个 Window 对应着一个 ViewRootImpl 和 一个 VIew。这个 View 就是被 ViewRootImpl
操作的。
一个小栗子,我们都只 Actiivty 中 会创建一个 Window 对象。
setContentView
方法中的 View 最终也会被添加到 Window 对象中的DecorView
中,也就是说一个 Window 中对应着一个 View。这个 View 是被RootViewImpl
操作的。WindowManager 就是入口。通过 WindowManager 的 addView 添加一个 Window(也可以理解为 View),然后就会创建一个 ViewRootImpl,来对 view 进行操作,最后将 View 渲染到屏幕的窗口上。
例如 Activity 中,在 onresume 执行完成后,就会获取 Window 中的 DecorView,然后通过 WindowManager 把 DecorView 添加到窗口上,这个过程中是由 RootViewImpl 来完成测量,绘制,等操作的。
View 的三大流程都是通过 RootViewImpl
来完成的,在 ActivityThread
中,当 Activity 对象被创建完毕后,在 onResume
后,就会通过 WindowManager 将 DecorView 添加到窗口上,在这个过程中会创建 ViewRootImpl
:
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { // ..... final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); final Activity a = r.activity; 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; if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //添加 decor 到 window 中 wm.addView(decor, l); } else { a.onWindowAttributesChanged(l); } } } //.... }
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //检查参数是否合法 if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; //..... ViewRootImpl root; View panelParentView = null; synchronized (mLock) { //创建 ViewRootImpl root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //将 Window 所对应的 View,ViewRootImp,params 顺序添加到列表中,这一步是为了方便更新和删除 View mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { //把 Window 对应的 View 设置给创建的 ViewRootImpl //通过 ViewRootImpl 来更新界面并添加到 WIndow中。 root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; attrs = mWindowAttributes; //请求布局,执行 View 的绘制方法 requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); //将 Window 添加到屏幕上,mWindowSession 实现了 IWindowSession接口,是 Session 的 Binder 对象。 // addToDisplay 是一次 AIDL 的过程,通知 WindowManagerServer 添加 Window res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); setFrame(mTmpFrame); } //设置当前 View 的 Parent view.assignParent(this); } } }
//请求布局 public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } //检测当前线程,如果不是主线程,直接抛出异常 void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } } final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } } void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } }
在上面代码中,调用 requestLayout
请求布局,最终会执行到 performTraversals
方法中。在这个方法中会调用 View
的 measure()
,layout()
,draw()
方法。
private void performTraversals() { // cache mView since it is used so much below... final View host = mView; //想要展示 Window 的宽高 int desiredWindowWidth; int desiredWindowHeight; //第一次执行 if (mFirst) { //.... //将窗口信息附加到 View 上。 host.dispatchAttachedToWindow(mAttachInfo, 0); //.... } else { desiredWindowWidth = frame.width(); desiredWindowHeight = frame.height(); if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); mFullRedrawNeeded = true; mLayoutRequested = true; windowSizeMayChange = true; } } //开始进行布局准备 boolean windowShouldResize = layoutRequested && windowSizeMayChange && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && frame.width() < desiredWindowWidth && frame.width() != mWidth) || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && frame.height() < desiredWindowHeight && frame.height() != mHeight)); windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM; windowShouldResize |= mActivityRelaunched; final boolean computesInternalInsets = mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners() || mAttachInfo.mHasNonEmptyGivenInternalInsets; if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { mForceNextWindowRelayout = false; //.... if (!mStopped || mReportNextDraw) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || contentInsetsChanged || updatedConfiguration) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); if (measureAgain) { //View 的测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); } layoutRequested = true; } } } //.......... final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { // View 的布局 performLayout(lp, mWidth, mHeight); //..... } //...... boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; if (!cancelDraw) { // View 的绘制 performDraw(); } else { if (isViewVisible) { // Try again scheduleTraversals(); } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } } mIsInTraversal = false; }
ViewRootImpl
调用 performMeasure
执行 Window 对应的 View 测量。
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
在 performMeasure
方法中就会执行 View 的 measure 方法,在其中会计算一下约束信息,然后就会调用 onMeasure 方法,
ViewRootImpl
调用 performLayout
执行 Window 对应 View 的布局
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { mScrollMayChange = true; mInLayout = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); try { // 调用 layout 方法进行布局 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); mInLayout = false; int numViewsRequestingLayout = mLayoutRequesters.size(); if (numViewsRequestingLayout > 0) { ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false); if (validLayoutRequesters != null) { mHandlingLayoutInLayoutRequest = true; // Process fresh layout requests, then measure and layout int numValidRequests = validLayoutRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = validLayoutRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during layout: running second layout pass"); // 请求对该 View 进行布局,该操作会导致此 View 被重新测量,布局,绘制 view.requestLayout(); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true; host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); mHandlingLayoutInLayoutRequest = false; // Check the valid requests again, this time without checking/clearing the // layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters != null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(new Runnable() { @Override public void run() { int numValidRequests = finalRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); // 请求对该 View 进行布局,该操作会导致此 View 被重新测量,布局,绘制 view.requestLayout(); } } }); } } } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } mInLayout = false; }
通过上面代码可以看出,在 layout 布局期间,有可能会对 View 进行 requestLayout
重新进行测量,布局,绘制。
ViewRootImpl
通过调用 performDraw
执行 Window 对应 View 的绘制。
private void performDraw() { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { return; } else if (mView == null) { return; } final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || mNextDrawUseBlastSync; mFullRedrawNeeded = false; mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(); addFrameCallbackIfNeeded(); try { //绘制 boolean canUseAsync = draw(fullRedrawNeeded); if (usingAsyncReport && !canUseAsync) { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null); usingAsyncReport = false; } } finally { mIsDrawing = false; Trace.traceEnd(Trace.TRACE_TAG_VIEW); } //... }
private boolean draw(boolean fullRedrawNeeded) { //........ //通知 View 上注册的绘制事件 mAttachInfo.mTreeObserver.dispatchOnDraw(); boolean useAsyncReport = false; if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty || mNextDrawUseBlastSync) { if (isHardwareEnabled()) { //调用 Window 对应 View 的 invalidate 方法 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this); } else { // 绘制 View if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) { return false; } } } if (animating) { mFullRedrawNeeded = true; scheduleTraversals(); } return useAsyncReport; } void invalidate() { mDirty.set(0, 0, mWidth, mHeight); if (!mWillDrawSoon) { scheduleTraversals(); } }
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) { // Draw with software renderer. final Canvas canvas; try { canvas = mSurface.lockCanvas(dirty); // TODO: Do this in native canvas.setDensity(mDensity); } try { if (DEBUG_ORIENTATION || DEBUG_DRAW) { Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" + canvas.getWidth() + ", h=" + canvas.getHeight()); //canvas.drawARGB(255, 255, 0, 0); } // View 绘制 mView.draw(canvas); drawAccessibilityFocusedDrawableIfNeeded(canvas); } finally { } return true; }
Android 开发艺术探索
如果本文对你有帮助,请点赞支持,谢谢!如果有任何问题,可直接在下方评论,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。