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 ...
随机推荐
- HttpServletRequest继承字ServletRequest的常用方法
//获取请求的完整路径String origUrl = req.getRequestURL().toString(); //获取查询的参数String queryStr = req.getQueryS ...
- 133个Java面试问题列表
转载: 133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...
- 【C#】Lamada表达式演变过程
static void Main() { //第一步 委托实例调用 Func<string, int> test = new Func<string, int>(getLeng ...
- github 笔记(一)
笔记预留 0. echo "# Try" >> README.md git init git add README.md git commit -m "fir ...
- Implementing x / 6 Using Only Bit Manipulations
This is an interesting question from one of the lab assignments in Introduction to Computer Systems, ...
- SpringMVC框架 注解 (转)
原文地址:http://www.cnblogs.com/yjq520/p/6734422.html 1.@Controller @Controller 用于标记在一个类上,使用它标记的类就是一个Spr ...
- COMP COMP-3
Comp (Computational) Comp (with no suffix) leaves the choice of the data type to the compiler writer ...
- 【HDU 6017】 Girls Love 233 (DP)
Girls Love 233 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- 矩阵&行列式
# 代数 排列 对换,对于一个排列操作,对于一个偶排列一次对换之后变为奇排列 反之变为偶排列 行列式 N阶行列式室友N^2个数aij(i,j = 1,2,3,...n) 行列式的数=\(\sum_ { ...
- Codeforces 408 E. Curious Array
$ >Codeforces \space 408 E. Curious Array<$ 题目大意 : 有一个长度为 \(n\) 的序列 \(a\) ,\(m\) 次操作,每一次操作给出 \ ...