如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析(二)...
FrameLayout和LinearLayout性能PK
FrameLayout
LinearLayout
Measure:2.058ms
Layout:0.296ms
draw:3.857ms
FrameLayout
Measure:1.334ms
Layout:0.213ms
draw:3.680ms
从这个数据来使用LinearLayout,仅嵌套一个LinearLayou,在onMeasure就相关2倍时间和FrameLayout相比,layout和draw的过程两者相差无几,考虑到误差的问题,几乎可以认为两者不分伯仲
看下FrameLayout的源码,做了什么?
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int count = getChildCount();final boolean measureMatchParentChildren =MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;//当FrameLayout的宽和高,只有同时设置为match_parent或者指定的size,那么这个//measureMatchParentChlidren = false,否则为true。下面会用到这个变量mMatchParentChildren.clear();int maxHeight = 0; int maxWidth = 0;int childState = 0; //宽高的期望类型for (int i = 0; i < count; i++) { //一次遍历每一个不为GONE的子viewfinal View child = getChildAt(i); if (mMeasureAllChildren || child.getVisibility() != GONE) {//去掉FrameLayout的左右padding,子view的左右margin,这时候,再去//计算子view的期望的值measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);final LayoutParams lp = (LayoutParams) child.getLayoutParams();/*maxWidth找到子View中最大的宽,高同理,为什么要找到他,因为在这里,FrameLayout是wrap-content.他的宽高肯定受子view的影响*/maxWidth = Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);maxHeight = Math.max(maxHeight,child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);childState = combineMeasuredStates(childState, child.getMeasuredState());/*下面的判断,只有上面的FragLayout的width和height都设置为match_parent 才不会执行此处的mMatchParentChlidren的list里存的是设置为match_parent的子view。结合上面两句话的意思,当FrameLayout设置为wrap_content,这时候要把所有宽高设置为match_parent的子View都记录下来,记录下来干什么呢?这时候FrameLayout的宽高同时受子View的影响*/if (measureMatchParentChildren) {if (lp.width == LayoutParams.MATCH_PARENT ||lp.height == LayoutParams.MATCH_PARENT) {mMatchParentChildren.add(child);}}}}// Account for padding toomaxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();// Check against our minimum height and widthmaxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());// Check against our foreground's minimum height and widthfinal Drawable drawable = getForeground();if (drawable != null) {maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());}//设置测量过的宽高setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState << MEASURED_HEIGHT_STATE_SHIFT));count = mMatchParentChildren.size();//这个大小就是子view中设定为match_parent的个数if (count > 1) {for (int i = 0; i < count; i++) {//这里看上去重新计算了一遍final View child = mMatchParentChildren.get(i);final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidthMeasureSpec;int childHeightMeasureSpec;/*如果子view的宽是match_parent,则宽度期望值是总宽度-padding-margin如果子view的宽是指定的比如100dp,则宽度期望值是padding+margin+width这个很容易理解,下面的高同理*/if (lp.width == LayoutParams.MATCH_PARENT) {childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -getPaddingLeftWithForeground() - getPaddingRightWithForeground() -lp.leftMargin - lp.rightMargin,MeasureSpec.EXACTLY);} else {childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,getPaddingLeftWithForeground() + getPaddingRightWithForeground() +lp.leftMargin + lp.rightMargin,lp.width);}if (lp.height == LayoutParams.MATCH_PARENT) {childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -getPaddingTopWithForeground() - getPaddingBottomWithForeground() -lp.topMargin - lp.bottomMargin,MeasureSpec.EXACTLY);} else {childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,getPaddingTopWithForeground() + getPaddingBottomWithForeground() +lp.topMargin + lp.bottomMargin,lp.height);}//把这部分子view重新计算大小child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}}}
加了一个嵌套,onMeasure时间,多了将近一倍,原因在于:LinearLayout在某一方向onMeasure,发现还存在LinearLayout。将触发 if (useLargestChild && (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
mTotalLength = 0;
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
}
if (child.getVisibility() == GONE) {
i += getChildrenSkipCount(child, i);
continue;
}
}
因为二级LinearLayout父类是Match_parent,所以就存在再层遍历。在时间就自然存在消耗。
结论
1.RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2.RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
3.在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最后再思考一下文章开头那个矛盾的问题,为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。
4.能用两层LinearLayout,尽量用一个RelativeLayout,在时间上此时RelativeLayout耗时更小。另外LinearLayout慎用layout_weight,也将会增加一倍耗时操作。由于使用LinearLayout的layout_weight,大多数时间是不一样的,这会降低测量的速度。这只是一个如何合理使用Layout的案例,必要的时候,你要小心考虑是否用layout weight。总之减少层级结构,才是王道,让onMeasure做延迟加载,用viewStub,include等一些技巧。
如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析(二)...相关推荐
- Android中常见五种布局管理器——RelativeLayout、LinearLayout、FrameLayout、TableLayout、GridLayout
目录 布局管理器 RelativeLayout 常见属性 Relative的实践操作(实现软件更新界面) LinearLayout 常见属性 LinearLayout的实践操作(模范登录以及微信底部) ...
- Android官方开发文档Training系列课程中文版:布局性能优化之布局层级优化
原文地址:http://android.xsoftlab.net/training/improving-layouts/index.html 引言 布局是直接影响用户体验的关键部分.如果实现的不好,那 ...
- android 减少布局层级,Android 布局优化
布局优化主要从以下几点进行着手 减少布局层次 和 复杂度 优化绘制流程 按需加载布局 减少布局层次 和 复杂度 首先我们可以通过以下工具分析界面布局的结构 查看布局树工具:Hierarchy View ...
- 布局检测与优化(一):布局层级优化
在本文中,我们将全面解析UX中视觉层级的关键原则,探讨如何使用视觉层级来改进产品并优化用户体验. UX中的视觉层级 自设计之初,我们已经使用它来传达重要的信息.设计中的每个元素都应有助于改善用户体验, ...
- Android优化五:布局优化
1.减少布局层级 Google在API文档中建议View树的高度不宜超过10层. 以前我们用Eclipse写代码时,自动生成的模板是以LinearLayout为根节点的,但是后面变成了Relative ...
- 网页优化中,网站页面结构该注意什么?
网站页面结构即网页内容布局,网站页面结构的创建就是要对网页的内容进行规划布局,合理的网站页面结构总是很受搜索引擎蜘蛛的欢迎,网站页面结构也能直接影响页面的用户体验及相关性,还能影响网站整体结构及页面被 ...
- CVPR 2022 | CNN自监督预训练新SOTA:上交、Mila、字节联合提出具有层级结构的图像表征自学习新框架...
©作者 | 机器之心编辑部 来源 | 机器之心 来自上海交通大学.Mila 魁北克人工智能研究所以及字节跳动的研究者提出了一种具有层级语义结构的自监督表征学习框架,在 ImageNet 数据集上预训练 ...
- 顺风车Android性能优化之View布局优化
一.问题背景 在开发过程中,往往会听到 "性能优化" 这个概念,这个概念很大,比如网络性能优化.耗电量优化等等,对 RD 而言,最容易做的或者是影响最大的,应该是 View 的性能 ...
- Android性能优化系列之布局优化,Android程序员校招蚂蚁金服
25 26 rInflate方法关键代码 void rInflate(XmlPullParser parser, View parent, Context context, AttributeSet ...
- 源码分析 merge 标签减少布局层级的秘密(Android Q)
源码分析 merge 标签减少布局层级的秘密(Android Q) 我在<Android 渲染性能优化--你需要知道的一切!>一文中介绍过,merge 标签用于减少 View 树的层次来优 ...
最新文章
- [BZOJ3337] ORZJRY I --块状链表大毒瘤
- java 视频切片_关于视频播放、视频切片、跨域访问视频
- css 命名规范 BEM
- Python_Day4_函数
- Linq中两种更新操作
- Sublime text 简单配置
- kotlin函数式编程_我最喜欢的Kotlin函数式编程示例
- ie6的png24问题
- android编辑框显示,为EditText输入框加上提示信息
- 842. 将数组拆分成斐波那契序列
- 达观智能制造知识图谱平台助力实现先进制造业“十四五”规划
- 【机器学习入门到精通系列】元胞自动机和代码举例(这一篇就够了!)
- 打砖块 如何实现三个球 java_小球弹砖块游戏(JAVA)
- 系统加速批处理文件:清理无用共享、内存及系统垃圾
- Machine learning techniques to enable closed-loop control in anesthesia-笔记
- OSAL(操作系统抽象层)
- 第三十八章 短语动词
- 操作无法完成因为文件已在syayem中打开怎么处理删除文件。
- xmind可以画流程图吗_xmind8可以画流程图吗
- c语言无符号整型越界,整型输出越界问题