欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Android View 的绘制流程

Android View 的绘制流程

2024/10/25 15:30:17 来源:https://blog.csdn.net/wilanzai/article/details/142387632  浏览:    关键词:Android View 的绘制流程


view作为构成android界面的基本元素,深入了解view的绘制流程对开发人员来说是很有必要的。

我们创建一个Activity都会在onCreate方法中写setContentView(layoutResId),把我们的布局传进去,那此时我们的布局就添加到屏幕上了吗?当然不是的。那我们的这个布局是在什么时候添加进屏幕的呢?

在ActivityThread.java 的handleResumeActivity中

//ActivityThread.java
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean
isForward, String reason) {
//...
wm.addView(decor, l);
//...
}

这里调用wm的addView,才把DecorView添加到窗口,wm其实就是WindowManagerImpl,接着我们跟进到WindowManagerImpl的addView

//WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyTokens(params);mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());
}

这里调用的是mGlobal的addView方法,mGlobal其实就是WindowManagerGlobal,是管理整个进程所有窗口信息的,接下来看看WindowManagerGlobal的addView方法

public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow, int userId) {//...final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;ViewRootImpl root;if (windowlessSession == null) {root = new ViewRootImpl(view.getContext(), display);} else {root = new ViewRootImpl(view.getContext(), display,windowlessSession);}
//为DecorView设置LayoutParamsview.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);root.setView(view, wparams, panelParentView, userId);//...  
}

接下来才到关键的地方了,ViewRootImpl的setView方法

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,int userId) {//...//遍历view树逻辑requestLayout();//...//将窗口添加到WMS上面res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(),mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibilities(), inputChannel,mTempInsets,mTempControls);//...//将ViewRootImpl设置为DecorView的parentview.assignParent(this);
}

在这里的requestLayout,最终会走到performTraversals方法,这里才真正开始遍历view的measure、layout、draw等流程

private void performTraversals() {//...//预测量,最多会执行3次onMeasure// Ask host how big it wants to bewindowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),desiredWindowWidth, desiredWindowHeight);//...// Ask host how big it wants to beperformMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//...performLayout(lp, mWidth, mHeight);//...if (!performDraw() && mSyncBufferCallback != null) {mSyncBufferCallback.onBufferReady(null);}//...
}

预测量

private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {//...if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {final DisplayMetrics packageMetrics = res.getDisplayMetrics();//默认320dpres.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);if (baseSize != 0 && desiredWindowWidth > baseSize) {childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width,lp.privateFlags);childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,lp.privateFlags);//第一次预测量performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);if((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0 {goodMeasure = true;} else {//宽度不够则再将剩余空间一般给child继续测量baseSize = (baseSize + desiredWindowWidth) / 2;childWidthMeasureSpec = getRootMeasureSpec(baseSize,lp.width,lp.privateFlags);performMeasure(childWdithMeasureSpec,childHeightMeasureSpec);if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {if (DEBUG_DIALOG) Log.v(mTag, "Good!");goodMeasure = true;}}}}//如果宽度还不满足,则将全部宽度给child去测量if (!goodMeasure) {childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,lp.privateFlags);childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,lp.privateFlags);performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()){windowSizeMayChange = true;}}
}

测量

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);}
}
//View.java
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {//...//最终执行到对应view的onMeasure中onMeasure(widthMeasureSpec, heightMeasureSpec);//...
}

布局

//ViewRootImpl.java
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {//...host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());//...
}//View.java
public void layout(int l, int t, int r, int b) {//...//在这里给左上右下去赋值,之后的getWidth和getHeight才能获取到值boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);//...//这里调用到对应view的onLayout方法onLayout(changed, l, t, r, b);//...
}

绘制

//ViewRootImpl.java
private boolean performDraw() {//...boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);//...
}private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {//...if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,scalingRequired, dirty, surfaceInsets)) {return false;}
}private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty, Rect surfaceInsets) {//...//执行到对应view的draw方法mView.draw(canvas);//...
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com