View绘制流程分析
Posted 哈特谢普苏特
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了View绘制流程分析相关的知识,希望对你有一定的参考价值。
我们知道在onCreate()方法中setContentView()方法是将xml文件解析到DecorView上,那么DecorView又是什么时候显示在屏幕上的呢?
我们都知道activity的生命周期中onResume()做了很多工作,而onResume()的调用如上图所示。在ActivityThread中,handleResumeActivity()方法不光调用了performActivity()方法最终实现对onResume()方法的调用,还进行了以下操作。
而ViewManger是一个接口,实际上真正的是WindowMangerImpl
真正调用的是WindowManagerGlobal的addView()方法
方法中创建了ViewRootImpl
mViews.add(view); //DecorView
mRoots.add(root); //ViewRootImpl
mParams.add(wparams) //WindowManager.LayoutParams
root.setView(view, wparams, panelParentView);//将view和viewRootImpl进行绑定
去查找ViewRootImpl的setView()方法,最重要的就是内部调用了requestLayout()方法
在requestLayout()方法中,首先会checkThread()检查当前线程是否为主线程,然后执行scheduleTraversals()方法进行真正的绘制。
scheduleTraversals()中通过mTraversalRunable执行doTraversal()方法
最终执行到performTraversals()方法,绘制view就是在该方法中执行的。
performTraversals()方法很长,做了很多事情
1. windowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight);注释也说明了,是询问想要的大小,即进行预测量
只有wrap_content的情况才需要协商
a.首先通过res.getValue给定一个初始值进行测量
b.performMeasure()
c.if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0)
如果测量结果满意,则设置为true
d.如果不满足if条件,则修改baseSize,
baseSize = (baseSize+desiredWindowWidth)/2,
重新进行performMeasure()
e.如果还不满意,则将窗口宽高均赋给,进行第三次performMeasure()
如果windowSizeMayChange = true,则表示还需要进行测量
2. relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);//布局窗口 实际在WMS中被调用
3.performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);//控件数的测量 (最多会调用4次performMeasure())
执行view本身的measure()方法,measure()方法一定要调用setMesureDemension()方法
4.performLayout(lp,mWidth,mHeight)
类似的,调用view的layout()方法
可以进行layoutChange的监听,从而获悉改变
如果是view,则在测量的时候需要加上自己的padding,如果是容器,则需要加上Margin
5.performDraw();//绘制
performDraw()方法内部调用了draw()
scrollToRectOrFocus(null, false) 计算滚动,如键盘的弹出?
绘制分为两种情况:硬件加速or软件加速
软件和硬件绘制的流程、区别?待补充 硬件绘制效果更好 (软件绘制会将所有的都进行绘制)
无论何种,都会调用view的draw()方法,即熟知的(背景,dispatchDraw()的过程),自定义控件一般不会重写该方法
canvas 也有软硬件之分
measure()方法是为了测量并确定子控件的大小,layout()中调用的onLayout()方法是为了确定当前view在父控件中的位置
在ViewRootImpl的setView()方法中,还执行了其它操作。目的是将窗口添加到WMS上、
给自己当前的view设置parent
在ViewRootImpl的构造器
mThread = Threag.currentThread() //拿到创建它的线程
mDirty = new Rect() //脏区域
mAttachInfo = new View.AttachInfo() //保存当前窗口的一些信息
WindowMangerImpl 确定View属于哪个父窗口
WindowManagerGlobal 管理整个进程 所有的窗口信息
ViewRootImpl 是WindowManagerGlobal的实际操作者,操作自己的窗口
以上是关于View绘制流程分析的主要内容,如果未能解决你的问题,请参考以下文章