一个 forceLayout() 和 requestLayout() 的测试
两个view:
一个是系统默认的FrameLayout, A
一个是自己自定义的MyView extends View,重载了onMeasure函数(): B
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO Auto-generated method stub
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // Log.e(TAG, "onMeasure " + MeasureSpec.getSize(widthMeasureSpec)
- // + " " + MeasureSpec.getSize(heightMeasureSpec));
- setMeasuredDimension(MeasureSpec.makeMeasureSpec(mW-=10, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mH-=10, MeasureSpec.EXACTLY));
- }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Log.e(TAG, "onMeasure " + MeasureSpec.getSize(widthMeasureSpec)
// + " " + MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension(MeasureSpec.makeMeasureSpec(mW-=10, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mH-=10, MeasureSpec.EXACTLY));
}
逻辑很简单,每次只要B的onMeasure被触发,那么B的尺寸就原来小10.
A包含B,
几个测试case: (measure() 是final的,无法覆盖,不过B的measure()应该是每次被调到的)
1. A.requestLayout(); 不会调用到B.onMeasure() 和 B.onLayout(), 会调用B.layout() (注意连draw()都没有被调到,这意味着B被A认为完全没变,不需要重绘)
2. B.forceLayout(); A.requestLayout() 会调用到B的.onMeasure() 和 onLayout() 以及 layout(), draw(), onDraw()
3. B.requestLayout() 会调用到B的.onMeasure() 和 onLayout() 以及 layout(),draw(), onDraw()
4. B.invalidate() B的layout(), onLayout() 和 onMeasure() 没有被调到,只有 draw() 和 onDraw() 被调到.
5 A.invalidate() B的所有函数都不会被调到.
这个结果也符合code的逻辑,forceLayout()如果注释说的一样,是在下一次layout bypass 的过程(自己不会发起一次layout bypass)中,会强制的重新onMeasure和onLayout()
而requestLayout() 除了干forceLayout()的事情将自己的FORCE_LAYOUT标志位设上外,还会发起一次layout pass,
在layout bypass 从 A 传到 B时,虽然 A 的 onMeasure() 和 onLayout() 会调用 B 的 measure() 和 layout(), 但是,因为 B的layout状态没有什么改变,因此
onMeasure()和 onLayout()不会被调用.
在当前4.4的code:
- public void forceLayout() {
- ................................................
- mPrivateFlags |= PFLAG_FORCE_LAYOUT;
- mPrivateFlags |= PFLAG_INVALIDATED;
- }
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- ...............................................................
- if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
- .......................................................
- int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
- mMeasureCache.indexOfKey(key);
- if (cacheIndex < 0 || sIgnoreMeasureCache) {
- ..................................................
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
- } else {
- long value = mMeasureCache.valueAt(cacheIndex);
- // Casting a long to int drops the high 32 bits, no mask needed
- setMeasuredDimension((int) (value >> 32), (int) value);
- mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
- }
- ......................................................................................
- mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
- }
- .............................................................................
- }
- public void layout(int l, int t, int r, int b) {
- .....................................................
- if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
- onLayout(changed, l, t, r, b);
- mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
- ...................................................................
- }
- mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
- mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
- }
public void forceLayout() {
................................................
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
mPrivateFlags |= PFLAG_INVALIDATED;
} public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
...............................................................
if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
.......................................................
int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
..................................................
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimension((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
......................................................................................
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}
.............................................................................
} public void layout(int l, int t, int r, int b) {
.....................................................
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ...................................................................
} mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
}
可见forceLayout()可以导致onMeasure() 和 onLayout(). 而requestLayout() 干的事情比forceLayout()只多不少.
View的forceLayout后面一般会紧跟着View的measure(), 这样可以把view的measuredSize 通过 setMeasuredDimension 设上.
而PFLAG_INVALIDATED 这个flag 应该是标记 重绘的。
而requestLayout()/forceLayout() 设置的另一个flag PFLAG_FORCE_LAYOUT,也一定可以在measure()中 将PFLAG_LAYOUT_REQUIRED flag给打上,
而PFLAG_LAYOUT_REQUIRED 则是可以保证了在调用 layout()函数时,onLayout() 函数会被调用到.
还有一点,之前没有仔细看, View的measure(A, B) 函数:
- 如果有PFLAG_FORCE_LAYOUT 或者 本次的measure的尺寸 A, B 和 之前的尺寸不一样
- if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
- widthMeasureSpec != mOldWidthMeasureSpec ||
- heightMeasureSpec != mOldHeightMeasureSpec) {
- ........................................................
- 这一步其实是从之前的MeasureCache里找是否存在 和 本次的measure尺寸一致的 cache
- int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
- mMeasureCache.indexOfKey(key);
- 如果没有找到,那么就调用onMeasure, 一般来说,调用了onMeasure才能真正的setMeasuredDimension
- if (cacheIndex < 0 || sIgnoreMeasureCache) {
- // measure ourselves, this should set the measured dimension flag back
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
- } else {
- 如果找到有cache,那么就将cache的值 设为 setMeasuredDimension
- long value = mMeasureCache.valueAt(cacheIndex);
- // Casting a long to int drops the high 32 bits, no mask needed
- setMeasuredDimension((int) (value >> 32), (int) value);
- mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
- }
- }
- ..............................................
- mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
- ..............................................
- mOldWidthMeasureSpec = widthMeasureSpec;
- mOldHeightMeasureSpec = heightMeasureSpec;
- mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
- (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
如果有PFLAG_FORCE_LAYOUT 或者 本次的measure的尺寸 A, B 和 之前的尺寸不一样
if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) { ........................................................ 这一步其实是从之前的MeasureCache里找是否存在 和 本次的measure尺寸一致的 cache
int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
mMeasureCache.indexOfKey(key);
如果没有找到,那么就调用onMeasure, 一般来说,调用了onMeasure才能真正的setMeasuredDimension
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
如果找到有cache,那么就将cache的值 设为 setMeasuredDimension
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimension((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
} ..............................................
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; ..............................................
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec; mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
这说明调用measure(A, B), 只要尺寸变化,都会影响 MeasuredHeight/Width
借鉴:http://blog.csdn.net/fyfcauc/article/details/41895509
一个 forceLayout() 和 requestLayout() 的测试的更多相关文章
- Huxley 是一个用于Web应用 UI 测试的工具
Huxley 是一个用于Web应用 UI 测试的工具,由 Pete Hunt 和 Maykel Loomans 用 Python 开发. UI 测试比较令人头疼. UI测试不好写,而且很容易失效: ...
- Selenium也是一个用于Web应用程序测试的工具
Selenium也是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE.Mozilla Firefox.Mozilla Suite ...
- 一个类似于postman的协议测试工具
协议测试工具使用postman相当便捷,不过有一个问题,就是每个人都要装一个这个东西,并且测试文件导来导去,还是觉得麻烦了点. 最重要的是postman不能修改,有一些定制功能postman明显力不从 ...
- 一个好用的压力测试工具tsung
一个好用的压力测试工具tsung 前段时间一直在忙各种事情,快三周没弄过引擎了,今天有点时间,正好之前写的服务器引擎也到了收尾测试的阶段,于是就研究了下怎么测试服务器压力. ...
- 一个"如何使用示波器安全测试接市电电路板"的问题
最近犯了一个错误测试操作: 测试场景:直接从市电插座取电接入3W非隔离开关电源电路板,使用示波器测试输出电压,此时示波器通过另外一个插座直接从市电取电 测试后果:在将示波器接到输出负极的一瞬间,漏电保 ...
- ios如何一个证书多台设备测试
在苹果开发者网站申请的证书,是授权mac设备的开发或者发布的证书,这意味着一个设备对应一个证书,但是99美元账号只允许生成3个发布证书,两个开发证书,这满足不了多mac设备的使用,使用p12文件可以解 ...
- 不会用ant打包、部署项目的工程师,不是一个好程序员(测试)
副标题:利用ant脚本 自动构建svn增量/全量 系统程序升级包 首先请允许我这样说,作为开发或测试,你一定要具备这种本领.你可以手动打包.部署你的工程,但这不是最好的方法.最好的方式就是全自动化的方 ...
- 实例--post请求,完成一个抽奖程序概率的测试
一个web项目测试,测试抽奖概率的正确性,写了一个小代码,验证概率 post和get请求的一个工具类 package kankan_interface; import java.io.IOExcept ...
- 一个基于集成jenkins的测试平台
(一)先看测试业务的情况: 有各种各样的任务包括代码构建.部署搭建.单元测试.功能自动化测试(包括许多模块的功能自动化测试,有十几个居多),性能测试.正确性验证:复杂一点的是这些任务在不同的测试阶段中 ...
随机推荐
- 720P、1080P、4K是什么意思?
什么是像素? 中文全称为图像元素.像素仅仅只是分辨率的尺寸单位,而不是画质. 从定义上来看,像素是指基本原色素及其灰度的基本编码. 像素是构成数码影像的基本单元,通常以像素每英寸PPI(pixels ...
- 诺基亚9 PureView正式发布
[手机中国新闻]当地时间2月24日下午16点,HMD在西班牙巴塞罗那正式发布了诸多新品,其中最吸睛的莫过于Nokia 9 PureView.作为全球首款五摄新机,Nokia 9 PureView后置五 ...
- C# 6.0 新特性 (三)
主构造函数 自动属性初始化表达式尤其适合与主构造函数结合使用.主构造函数为降低常见对象模式的繁琐程度提供了一种方法.此功能自五月以来已显著改进.更新包括: 主构造函数的可选实现主体:这将支持此前不受支 ...
- 【LOJ】#2351. 「JOI 2017/2018 决赛」毒蛇越狱
题解 没啥特别好的算法,是个讨论题,由于0 1 ?三类数位中最少的不会超过6 如果1不超过6,那么记录\(f1(S)\)为 \(\sum_{T \subset S} val(T)\)这个可以通过类似F ...
- Linux Shell 文本处理工具
Linux下使用Shell处理文本时最常用的工具: find.grep.xargs.sort.uniq.tr.cut.paste.wc.sed.awk: 提供的例子和参数都是最常用和最为实用的: 我对 ...
- elementUI 学习入门之 input 输入框
基础用法 <el-input v-model="input1" palcehoder="请输入"></el-input> var Mai ...
- 获取token
获取token 提示:openstack 这个是获取N版的方法 ,主要区别在于这个路径上(http://192.168.0.228:35357/v3/auth/tokens ),以前版本可能会是v2 ...
- 「COCI2016/2017 Contest #2」Bruza
「COCI2016/2017 Contest #2」Bruza 解题思路 : 首先对于任意时刻 \(i\) ,硬币一定移动到了深度为 \(i\) 的节点,所以第 \(i\) 时刻 Danel 一定染掉 ...
- WEB架构师成长之路 一
一 .你必须学习面向对象的基础知识 1.降低软件开发的复杂度 2.提高软件开发的效率 3.提高软件质量:可维护性,可扩展性,可重用性等. 提高软件质量:可维护性,可扩展性,可重用性等,再具体点,就是高 ...
- [SimpleOJ236]暴风雨
题目大意: 给你一棵n个点的树,以及m+q条信息. m条描述点a到b有边直接相连. q条描述点a和点b的LCA为c. 问有多少符合条件的以1为根的树. 思路: 状压DP. e[i]记录需要与点i直接相 ...