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的实际操作者,操作自己的窗口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值