View绘制流程分析

Posted 哈特谢普苏特

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了View绘制流程分析相关的知识,希望对你有一定的参考价值。

setContentView()做了什么

 

我们知道在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绘制流程分析的主要内容,如果未能解决你的问题,请参考以下文章

View绘制流程二:测量布局绘制

View的绘制流程源码分析

源码分析Android中View的绘制流程

源码分析Android中View的绘制流程

Android View 的测量流程详解

Android绘制源码分析(下)