invalidate和requestLayout方法源码分析
invalidate方法源码分析
/*** Mark the area defined by dirty as needing to be drawn. dirty代表需要重新绘制的脏的区域* If the view is visible, onDraw(Canvas) will be called at somepoint in the future.* This must be called from a UI thread. To call from a non-UI thread, callpostInvalidate().* <b>WARNING:</b> In API 19 and below, this method may be destructive todirty.* @param dirty the rectangle矩形 representing表示 the bounds of the dirty region地区*/public void invalidate(Rect dirty) {final int scrollX = mScrollX;final int scrollY = mScrollY;invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,dirty.right - scrollX, dirty.bottom - scrollY, true, false);}public void invalidate(int l, int t, int r, int b) {final int scrollX = mScrollX;final int scrollY = mScrollY;//实质还是调用invalidateInternal方法invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);}/*** Invalidate the whole view. 重新绘制整个View*/public void invalidate() {invalidate(true);}public void invalidate(boolean invalidateCache) {invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);}//这是所有invalidate的终极调用方法void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,boolean fullInvalidate) {......// Propagate繁殖、传播 the damage损害的(只需要刷新的) rectangle to the parent view.final AttachInfo ai = mAttachInfo;final ViewParent p = mParent;if (p != null && ai != null && l < r && t < b) {final Rect damage = ai.mTmpInvalRect;damage.set(l, t, r, b);//将需要刷新的区域封装到damage中p.invalidateChild(this, damage);//调用Parent的invalidateChild方法,传递damage给Parent}......}
由此可知,View的invalidate方法实质是将要刷新区域直接传递给了【父ViewGroup的invalidateChild方法】,这是一个从当前View向上级父View回溯的过程 。
public final void invalidateChild(View child, final Rect dirty) {ViewParent parent = this;......do {......//循环层层上级调用,直到ViewRootImpl会返回nullparent = parent.invalidateChildInParent(location, dirty);......} while (parent != null);}
这里面主要是一个循环,循环结束的条件是 parent == null,什么情况下parent为null呢?
@Overridepublic ViewParent invalidateChildInParent(int[] location, Rect dirty) {......//View调用invalidate最终层层上传到ViewRootImpl后最终触发了该方法scheduleTraversals();......return null;}
也就是上面说的,当层层上级传递到ViewRootImpl的invalidateChildInParent方法时,返回了null,结束了那个do while循环。

postInvalidate方法源码分析
public void postInvalidate() {postInvalidateDelayed(0);}public void postInvalidateDelayed(long delayMilliseconds) {// We try only with the AttachInfo because there's no point in invalidating// if we are not attached to our windowfinal AttachInfo attachInfo = mAttachInfo;//核心,实质就是调用了ViewRootImpl.dispatchInvalidateDelayed方法if (attachInfo != null) {attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);}}public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);mHandler.sendMessageDelayed(msg, delayMilliseconds);}
看见没有,通过ViewRootImpl类的Handler发送了一条MSG_INVALIDATE消息,继续追踪这条消息的处理可以发现:
public void handleMessage(Message msg) {......switch (msg.what) {case MSG_INVALIDATE:((View) msg.obj).invalidate();break;......}......}
看见没有,实质就是又在UI Thread中调用了View的invalidate()方法,所以可以说,除了调用所在线程不一样之外,其他的和invalidate()方法都是一样的。
invalidate与postInvalidate方法总结
- 直接调用invalidate方法,请求重新draw,但只会绘制调用者本身。
- 触发setSelection方法,请求重新draw,但只会绘制调用者本身。
- 触发setEnabled方法,请求重新draw,但不会重新绘制任何View包括该调用者本身。
- 触发requestFocus方法,请求View树的draw过程,只绘制"需要重绘"的View。
- 触发setVisibility方法, 当View可视状态在INVISIBLE转换VISIBLE时会间接调用invalidate方法,继而绘制该View。当View的可视状态转换为GONE状态时会间接调用requestLayout和invalidate方法,同时由于View树大小发生了变化,所以会请求measure过程以及draw过程,同样只绘制需要"重新绘制"的视图。
补充performTraversals方法调用时机
@Overridepublic void setContentView(View view, ViewGroup.LayoutParams params) {......//如果mContentParent为空进行一些初始化if (mContentParent == null) {installDecor();}......//把我们的view追加到mContentParentmContentParent.addView(view, params);......}
我们继续看下这个方法中所调用的addView方法,也就是ViewGroup的addView方法,如下:
public void addView(View child) {addView(child, -1);}public void addView(View child, int index) {......addView(child, index, params);}public void addView(View child, int index, LayoutParams params) {......//该方法稍后后面会详细分析requestLayout();//重点关注!!!invalidate(true);......}
看见addView调用invalidate方法没有?这不就真相大白了。当我们写一个Activity时,我们一定会通过setContentView方法将我们要展示的界面传入该方法,该方法会将我们的View通过addView追加到id为content的一个FrameLayout(ViewGroup)中,然后addView方法中通过调用invalidate(true)去通知触发ViewRootImpl类的performTraversals()方法,至此递归绘制我们自定义的所有布局。
requestLayout方法源码分析
public void requestLayout() {......if (mParent != null && !mParent.isLayoutRequested()) {//从这个View开始向上一直requestLayout,最终到达ViewRootImpl的requestLayoutmParent.requestLayout();}......}
看见没有,整个和invalidate类似,当我们触发View的requestLayout时其实质就是:层层向上传递,直到ViewRootImpl为止,最后触发ViewRootImpl的requestLayout方法。
@Overridepublic void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {checkThread();mLayoutRequested = true;//View调用requestLayout最终层层上传到ViewRootImpl后最终触发了该方法scheduleTraversals();}}
看见没有,依旧是和invalidate类似,并且最终调用的也是scheduleTraversals()这个方法,只是在上传过程中所设置的标记不同,最终导致对于View的绘制流程中所触发的方法不同而已。
requestLayout方法总结
- requestLayout()方法会调用【measure】过程和【layout】过程,不会调用【draw】过程,所以不会重新绘制任何View(包括该调用者本身)。
- 使用条件:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求父view重新调用他的onMeasure、onLayout来重新设置自己位置。
- 用途:有时我们在改变一个view 的内容之后,可能会造成显示出现错误,比如写ListView的时候 重用convertview中的某个TextView 可能因为前后填入的text长度不同而造成显示出错,此时我们可以在改变内容之后调用requestLayout方法加以解决。
invalidate和requestLayout方法源码分析的更多相关文章
- Java split方法源码分析
Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...
- Linq分组操作之GroupBy,GroupJoin扩展方法源码分析
Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...
- 【Java】NIO中Selector的select方法源码分析
该篇博客的有些内容和在之前介绍过了,在这里再次涉及到的就不详细说了,如果有不理解请看[Java]NIO中Channel的注册源码分析, [Java]NIO中Selector的创建源码分析 Select ...
- jQuery实现DOM加载方法源码分析
传统的判断dom加载的方法 使用 dom0级 onload事件来进行触发所有浏览器都支持在最初是很流行的写法 我们都熟悉这种写法: window.onload=function(){ ... } 但 ...
- jQuery.extend()方法和jQuery.fn.extend()方法源码分析
这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子: html代码如下: <!doctype html> ...
- jQuery.clean()方法源码分析(一)
在jQuery 1.7.1中调用jQuery.clean()方法的地方有三处,第一次就是在我之前的随笔分析jQuery.buildFramgment()方法里面的,其实还是构造函数的一部分,在处理诸如 ...
- HashMap put、get方法源码分析
HashMap.java的实现是面试必问的问题. JDK版本 java version "1.8.0_91" Java(TM) SE Runtime Environment (bu ...
- HashMap主要方法源码分析(JDK1.8)
本篇从HashMap的put.get.remove方法入手,分析源码流程 (不涉及红黑树的具体算法) jkd1.8中HashMap的结构为数组.链表.红黑树的形式 (未转化红黑树时) (转 ...
- Hystrix微服务容错处理及回调方法源码分析
前言 在 SpringCloud 微服务项目中,我们有了 Eureka 做服务的注册中心,进行服务的注册于发现和服务治理.使得我们可以摒弃硬编码式的 ip:端口 + 映射路径 来发送请求.我们有了 F ...
随机推荐
- css3实现立方体,并且自转效果
先是HTML 一个父div包含四个绝对定位的div <div class='container container--realistic'> <div class='cube cub ...
- (转)一些牛人榜样,多看看他们写的东西(后续整理牛人的blog等)
http://blog.csdn.net/ajian005/article/details/7697761
- docker export import后,导入镜像,启动时的错误,Error response from daemon: No command specified
Docker的流行与它对容器的易分享和易移植密不可分,用户不仅可以把容器提交到公共服务器上,还可以把容器导出到本地文件系统中.同样,我们也可以把导出的容器重新导入到Docker运行环境中.Docker ...
- golang中接口interface和struct结构类的分析
再golang中,我们要充分理解interface和struct这两种数据类型.为此,我们需要优先理解type的作用. type是golang语言中定义数据类型的唯一关键字.对于type中的匿名成员和 ...
- React Native 系列(三)
前言 本系列是基于React Native版本号0.44.3写的,相信大家看了本系列前面两篇文章之后,对于React Native的代码应该能看懂一点点了吧.本篇文章将带着大家来认识一下React N ...
- dp 神奇的口袋
有一个神奇的口袋,总的容积是40,用这个口袋可以变出一 些物品,这些物品的总体积必须是40. John现在有n(1≤n ≤ 20)个想要得到的物品,每个物品 的体积分别是a1,a2--an.Joh ...
- socketserver用法列子
socketserver socketserver内部使用IO多路复用以及“多线程”和“多进程”,从而实现并发处理多个客户端请求的scoket服务端.即,每个客户端请求连接到服务器时,socket服务 ...
- 一个安卓应用 多少个 dalvik 虚拟机
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 一个
- [BZOJ4237]稻草人(CDQ分治)
先按y排序,二分,两边递归下去,然后处理下半部分对上半部分的贡献,即左下点在下半部分,右上点在上半部分的合法矩形个数. 两个部分均按x排序,枚举右上点p,则左下点需要满足: 1.横坐标大于上半部分纵坐 ...
- Java虚拟机类加载机制--概述
一.虚拟机类概加载概述 虚拟机将描述类的Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以直接被虚拟机使用的Java类型 Java语言支持动态加载和动态连接. 二.虚拟机加载类 ...