分析Android中View的工作流程

在分析View的工作流程时,需要先分析一个很重要的类,MeasureSpec。这个类在View的测量(Measure)过程中会用到。

MeasureSpec

MeasureSpec是View的静态内部类,可以理解为是一种测量规格,是一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小。

SpecMode有三种模式,分别为:

  1. UNSPECIFIED:父容器不对View做限制
  2. EXACTLY:父容器已经检测出View所需的精确大小,View的大小为SpecSize中指定的值。
  3. AT_MOST:父容器指定了一个SpecSize,View的大小不大大于该值。

MeasureSpec与LayoutParams

系统通过MeasureSpec作为测量规格,对View进行测量,但在设置View的宽高时,都是通过LayoutParams,因此系统在测量View的时候,会将LayoutParams在父容器的约束下转换成MeasureSpec,然后根据确定的MeasureSepc得到View测量后的宽高。有几点需要说明:

  1. LayoutParams和父容器一起确定MeasureSpec;
  2. 对于DecorView,其MeasureSpec是由窗口的尺寸和自身的LayoutParams共同确定的;由于窗口尺寸是确定的,因此主要与DecorView自身的LayoutParams有关,具体的对应关系如下图描述:
  3. 对于普通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的绘制过程遵循如下几步:

  1. 绘制背景background.draw(canvas)
  2. 绘制自己(onDraw)
  3. 绘制children(dispatchDraw)
  4. 绘制装饰(onDrawScrollBars)

View绘制过程的传递是通过dispatchDraw来实现的,dispatchDraw会遍历调用所有子元素的draw方法,如此draw事件就一层层地传递了下去。

参考文献

[1] 任玉刚.Android开发艺术探索[M].电子工业出版社, 2015.9:1 - 507



本文链接:http://www.sguotao.top/Android进阶-2016-07-07-分析Android中View的绘制流程.html

原文地址:https://www.cnblogs.com/lijianming180/p/12276056.html

时间: 2024-08-24 12:09:20

分析Android中View的工作流程的相关文章

深入理解 Android 之 View 的绘制流程

概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定实现细节则可以日后再对相应源码进行研读.在进行实际的分析之前,我们先来看下面这张图: 我们来对上图做出简单解释:DecorView是一个应用窗口的根容器,它本质上是一个FrameLayout.DecorView有唯一一个子View,它是一个垂直LinearLayout,包含两个子元素,一个是Titl

Android中View绘制流程以及invalidate()等相关方法分析

前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (d

Android中View绘制流程以及invalidate()等相关方法分析(转载的文章,出处在正文已表明)

转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(mea

Android中View绘制流程分析

创建Window 在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建Window,将一个View add到WindowManager时,WindowManagerImpl创建一个ViewRoot来管理该窗口的根View.并通过ViewRoot.setView方法把该View传给ViewRoot. final void attach(Context context, ActivityThread aThread, Instrumentation

Android 中View的绘制机制源码分析 一

尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差不多半年没有写博客了,一是因为工作比较忙,二是觉得没有什么内容值得写,三是因为自己越来越懒了吧,不过最近我对Android中View的绘制机制有了一些新的认识,所以想记录下来并分享给大家.在之后的几篇博客中,我会给大家分享如下的内容: 1.View中measure(),layout(),draw()函数执行过程分析,带领大家详细分析View的尺寸测量过程,位置计算,并最终

Android 中View的绘制机制源代码分析 三

到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编辑器.这里之所以使用"下定决心"这个词.是由于毕竟Html编辑器使用好几年了.非常多习惯都已经养成了,要改变多年的习惯确实不易.相信这也是还有非常多人坚持使用Html编辑器的原因. 这也反应了一个现象.当人对某一事物非常熟悉时,一旦出现了新的事物想代替老的事物时,人们都有一种抵触的情绪,做

Android 中View的绘制机制源码分析 三

到目前为止,measure过程已经讲解完了,今天开始我们就来学习layout过程,不过在学习layout过程之前,大家有没有发现我换了编辑器,哈哈,终于下定决心从Html编辑器切换为markdown编辑器,这里之所以使用"下定决心"这个词,是因为毕竟Html编辑器使用好几年了,很多习惯都已经养成了,要改变多年的习惯确实不易,相信这也是还有很多人坚持使用Html编辑器的原因.这也反应了一个现象,当人对某一事物非常熟悉时,一旦出现了新的事物想取代老的事物时,人们都有一种抵触的情绪,做技术的

Android 中View的绘制机制源码分析 二

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要讲解了View的measure过程,今天我们就来学习ViewGroup的measure过程,由于ViewGroup只是一个抽象类,所以我们需要以一个具体的布局来分析measure过程,正如我上篇文章说的,我打算使用LinearLayout为例讲解measure过程,如果你还没有读过上篇文章,那么建议你先

源码解析Android中View的measure量算过程

Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View的布局及绘图机制>.量算是布局和绘图的基础,所以量算是很重要的一个环节.本文将从源码角度解析View的量算过程,这其中会涉及某些关键类以及关键方法. 对View进行量算的目的是让View的父控件知道View想要多大的尺寸. 量算过程概述 如果要进行量算的View是ViewGroup类型,那么ViewGr