上文创建好了DecorView,并通过setContentView方法将需要展示的view添加到基础布局中去,现在开始绘制View------>绘制完成------->展示
View的绘制流程
分为三步
一 绘制入口
ActivityThread就是我们常说的主线程或UI线程,ActivityThread的main方法是整个APP的入口
(附上ActivityThread理解及启动过程:https://blog.csdn.net/hzwailll/article/details/85339714)
找到handleMessage()方法,该方法是所有activity调用都会触发的,在里面会调用handlerResumeActivity()方法。最后跟踪到 windowManagerImpl ,找到addView()方法
@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }
会调用到mGlobal的addView()方法,进入源码查看
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //省略... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { // If there's no parent, then hardware acceleration for this view is // set from the application's hardware acceleration setting. final Context context = view.getContext(); if (context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } ViewRootImpl root; View panelParentView = null; //省略...... root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams);//给view设置参数 mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { root.setView(view, wparams, panelParentView);//将三个参数关联 } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
二 绘制的类和入口
然后追踪到root.setView方法。
/** * We have one child */ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; mAttachInfo.mDisplayState = mDisplay.getState(); mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); if (mWindowAttributes.packageName == null) { mWindowAttributes.packageName = mBasePackageName; } attrs = mWindowAttributes; setTag(); if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!"); } // Keep track of the actual window flags supplied by the client. mClientWindowLayoutFlags = attrs.flags; setAccessibilityFocus(null, null); if (view instanceof RootViewSurfaceTaker) { mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); if (mSurfaceHolderCallback != null) { mSurfaceHolder = new TakenSurfaceHolder(); mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); mSurfaceHolder.addCallback(mSurfaceHolderCallback); } } // Compute surface insets required to draw at specified Z value. // TODO: Use real shadow insets for a constant max Z. if (!attrs.hasManualSurfaceInsets) { attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/); } CompatibilityInfo compatibilityInfo = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); mTranslator = compatibilityInfo.getTranslator(); // If the application owns the surface, don't enable hardware acceleration if (mSurfaceHolder == null) { enableHardwareAcceleration(attrs); } boolean restore = false; if (mTranslator != null) { mSurface.setCompatibilityTranslator(mTranslator); restore = true; attrs.backup(); mTranslator.translateWindowLayout(attrs); } if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); if (!compatibilityInfo.supportsScreen()) { attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; mLastInCompatMode = true; } mSoftInputMode = attrs.softInputMode; mWindowAttributesChanged = true; mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED; mAttachInfo.mRootView = view; mAttachInfo.mScalingRequired = mTranslator != null; mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale; if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); } mAdded = true; int res; /* = WindowManagerImpl.ADD_OKAY; */ // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); //省略.... } } }
下面总结一下在ViewRootImpl 的requestLayout方法之前都做了哪些操作
然后我们继续查看源码,,从ViewRootImpl.requestLayout()的方法进入,
@Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); }
继续
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //省略... } }
mTraversalRunnable 我们注意到这个线程
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } //省略....
继续追踪这个方法
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } performTraversals();//上下都是调试信息 if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } }
继续追踪
三 View绘制三大步骤
private void performTraversals() { //... performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); //... performLayout(lp, mWidth, mHeight); //... performDraw(); }