分析Android中View的工作流程
在分析View的工作流程时,需要先分析一个很重要的类,MeasureSpec。这个类在View的测量(Measure)过程中会用到。
MeasureSpec
MeasureSpec是View的静态内部类,可以理解为是一种测量规格,是一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小。
SpecMode有三种模式,分别为:
- UNSPECIFIED:父容器不对View做限制
- EXACTLY:父容器已经检测出View所需的精确大小,View的大小为SpecSize中指定的值。
- AT_MOST:父容器指定了一个SpecSize,View的大小不大大于该值。
MeasureSpec与LayoutParams
系统通过MeasureSpec作为测量规格,对View进行测量,但在设置View的宽高时,都是通过LayoutParams,因此系统在测量View的时候,会将LayoutParams在父容器的约束下转换成MeasureSpec,然后根据确定的MeasureSepc得到View测量后的宽高。有几点需要说明:
- LayoutParams和父容器一起确定MeasureSpec;
- 对于DecorView,其MeasureSpec是由窗口的尺寸和自身的LayoutParams共同确定的;由于窗口尺寸是确定的,因此主要与DecorView自身的LayoutParams有关,具体的对应关系如下图描述:

- 对于普通View,其MeasureSpec是由父容器的MeasureSpec和自身的LayoutParams共同确定的。其对应关系如下图描述:

对普通View,简单总结一下:
- 当View采用固定宽/高的时候,不管父容器的MeasureSpec是什么,View的MeasureSpec都是精确模式并且其大小遵循Layoutparams中的大小。
- 当View的宽/高是match_parent时,如果父容器的模式是精准模式,那么View也是精准模式并且其大小是父容器的剩余空间;如果父容器是最大模式,那么View也是最大模式并且其大小不会超过父容器的剩余空间。
- 当View的宽/高是wrap_content时,不管父容器的模式是精准还是最大模式,View的模式总是最大模式并且大小不能超过父容器的剩余空间。
- 在UNSPECIFIED模式中,系统内部会进行多次Measure过程,才能确定View的宽高。
View的工作流程
ViewRoot是连接WindowManager与DecorView的纽带,View的绘制流程都是通过ViewRoot来完成的。
View的工作流程是从ViewRoot的performTraversals方法开始的,它经过measure、layout和draw三个过程才能最终将一个View绘制出来,其中measure用来测量View的宽和高,layout用来确定View在父容器中的放置位置,而draw则负责将View绘制在屏幕上。用一张 大专栏 分析Android中View的工作流程图来描述View的工作过程:
View的测量(Measure)过程
在View的Measure过程中,完成对View的测量,确定View的宽高。ViewRoot中的performTraversals()会依次调用ViewRoot中的performMeasure()、performLayout()和performDraw()三个方法,这三个方法分别完成顶级View的measure、layout和draw这三大流程。其中在performMeasure()中会调用View的measure()方法,在measure()方法中又会调用onMeasure()方法。在onMeasure()中将View宽/高的测量值传给setMeasuredDimension()方法,完成View的测量过程。
对于ViewGroup来说,除了完成自己的measure过程以外,还会遍历去调用所有子元素的measure()方法,各个子元素再递归去执行这个过程。和View不同的是,ViewGroup是一个抽象类,因此它没有重写View的onMeasure方法,因为不同的ViewGroup子类有不同的布局特性,这导致它们的测量细节各不相同。在ViewGroup的onMeasure()中最后也会调用setMeasuredDimension()方法,完成测量过程。
measure完成以后,通过getMeasuredWidth()/Height()方法就可以正确地获取到View的测量宽/高。需要注意的是,在某些极端情况下,系统可能需要多次measure才能确定最终的测量宽/高,在这种情形下,在onMeasure方法中拿到的测量宽/高很可能是不准确的。一个比较好的习惯是在onLayout方法中去获取View的测量宽/高或者最终宽/高。
View的布局(Layout)过程
Layout的作用是ViewGroup用来确定子元素的位置,ViewRoot中的performLayout()中会调用View的layout()方法,在layout()方法中onLayout()方法又会被调用。onLayout的具体实现同样和具体的布局有关,所以View和ViewGroup均没有真正实现onLayout方法。
当ViewGroup的位置被确定后,它在onLayout()中会遍历所有的子元素并调用其layout()方法,layout()方法确定View本身的位置,而onLayout()方法则会确定所有子元素的位置。
View的绘制(Draw)过程
Draw的作用是将View绘制到屏幕上面。View的绘制过程遵循如下几步:
- 绘制背景background.draw(canvas)
- 绘制自己(onDraw)
- 绘制children(dispatchDraw)
- 绘制装饰(onDrawScrollBars)
View绘制过程的传递是通过dispatchDraw来实现的,dispatchDraw会遍历调用所有子元素的draw方法,如此draw事件就一层层地传递了下去。
参考文献
[1] 任玉刚.Android开发艺术探索[M].电子工业出版社, 2015.9:1 - 507
本文链接:http://www.sguotao.top/Android进阶-2016-07-07-分析Android中View的绘制流程.html
分析Android中View的工作流程的更多相关文章
- Android 中View的工作原理
Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...
- Android中View的绘制流程(专题讲解)
Android中的UI视图有两种方式实现:.xml文件(实现代码和UI的分离)和代码实现. Android的UI框架基本概念: 1. Activity:基本的页面单元,Activity包含一个Wind ...
- 深入理解 Android 之 View 的绘制流程
概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...
- 【转】深入理解Android之View的绘制流程
概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...
- Android之View的绘制流程
本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定实现细 ...
- Android中View绘制流程以及invalidate()等相关方法分析(转载的文章,出处在正文已表明)
转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时 ...
- Android中View绘制流程以及invalidate()等相关方法分析(转)
转自:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴 ...
- Android中View绘制流程以及invalidate()等相关方法分析
[原文]http://blog.csdn.net/qinjuning 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简 ...
- 【转载】Android 中 View 绘制流程分析
创建Window 在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建Window,将一个View add到WindowManager时,Window ...
随机推荐
- Python笔记_第四篇_高阶编程_GUI编程之Tkinter_5.鼠标事件
1. 鼠标点击事件: 图示: 实例: import tkinter from tkinter import ttk # 创建主窗口__编程头部 win = tkinter.Tk() # 设置标题 wi ...
- 35)类和结构体类比---this
那么,为啥 Test a(10) , Test b(20) 然后 我a.getI() 取到的是10,而不是20 就能将那个 10 给 a 对象的 m1 是因为有 ...
- split - 拆分文件
拆分文件 # 每个文件的行数为1000行 split -l 1000 test.txt # 将test文件拆分,20M一个文件 split -b 20M test.txt test文件拆分,并且文件名 ...
- MySQL安装教程及Navicat连接MySQL报错:1251-Client does not support authentication protocol requested by server
MySQL安装可参考: MySql 8.0.18安装 此参考文章后面涉及到的密码修改,对本标题碰到的错误同样适用. 本文先讲如何安装,在讲碰到的1251问题.要直接看解决方案的朋友可以直接通过目录链接 ...
- scala编程(六)——函数式对象
Rational 的式样书 分数:rational number 是一种可以表达为比率 d n 的数字,这里的 n 和 d 是数字,其中 d 不能为零.n 被称作是分子:numerator,d 被称作 ...
- layui表格自动对齐
正常情况table应该是这样展示的 但是却展示成了这样 格子没对齐,找了半天原因发现是在table.render中的cols参数多了一个"," 不细心一点真看不出来 正常结构应是 ...
- spring boot学习4 多环境配置
说明: 在企业中,一个项目一般都有测试环境(test) .开发环境(dev).生产环境(pro)等等.在每个环境中,配置信息会不一样的.比如数据库.静态资源文件位置等都会不一样的. 那么使用sprin ...
- Python连接SQLServer2000
http://www.pymssql.org/en/stable/pymssql_examples.html 实例 import pymssql # 获取连接 conn = pymssql.conne ...
- POJ-1811-Prime Test(pollard_rho模板,快速找最小素因子)
题目传送门 sol:Pollard_Rho的模板题,刚看了Pollard_Rho和Miller_Rabin很多原理性的东西看不懂,只是记住了结论勉强能敲代码. Pollard_Rho #include ...
- OpenCV 图像平滑处理
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" us ...