今天,简单讲讲android里RelativeLayout和LinearLayout的性能比较。

之前,我看到代码优化时需要将界面扁平化,所以查询了如何优化解码,了解一下RelativeLayout和LinearLayout的性能,已经什么情况下使用RelativeLayout和LinearLayout。这里记录一下。

0. 前言

我们都知道,新建一个Android项目SDK会为我们自动生成的avtivity_main.xml布局文件,然后它的根节点默认是RelativeLayout,在我们的理解里貌似LinearLayout的性能是要比RelativeLayout更优的,比如作为顶级View的DecorView就是个垂直方向的LinearLayout,上面是标题栏,下面是内容栏,我们常用的setContentView()方法就是给内容栏设置布局。那么LinearLayout和RelativeLayout谁的性能更高呢,好吧其实我们都知道前者性能更高,那原因是什么呢?

 

1.   性能对比

一。LinearLayout和RelativeLayout的绘图的耗时比较:

LinearLayout

Measure:0.738ms
Layout:0.176ms
draw:7.655ms

RelativeLayout

Measure:2.280ms
Layout:0.153ms
draw:7.696ms
从这个数据来看无论使用RelativeLayout还是LinearLayout,layout和draw的过程两者相差无几,考虑到误差的问题,几乎可以认为两者不分伯仲,关键是Measure的过程RelativeLayout却比LinearLayout慢了一大截。

RelativewLayout的Measure方法:根据源码我们发现RelativeLayout会对子View做两次measure。这是为什么呢?首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,

而这个依赖关系可能和布局中View的顺序并不相同,在确定每个子View的位置的时候,就需要先给所有的子View排序一下。
又因为RelativeLayout允许A,B 2个子View,横向上B依赖A,纵向上A依赖B。所以需要横向纵向分别进行一次排序测量。
LinearLayout的Measure方法: 与RelativeLayout相比LinearLayout的measure就简单明了的多了,先判断线性规则,然后执行对应方向上的测量  

LinearLayout和RelativeLayout的measure的小结

从源码中我们似乎能看出,我们先前的测试结果中RelativeLayout不如LinearLayout快的根本原因是RelativeLayout需要对其子View进行两次measure过程。而LinearLayout则只需一次measure过程,所以显然会快于RelativeLayout,但是如果LinearLayout中有weight属性,则也需要进行两次measure,但即便如此,应该仍然会比RelativeLayout的情况好一点。

实验结果我们得之,两者绘制同样的界面时layout和draw的过程时间消耗相差无几,关键在于measure过程RelativeLayout比LinearLayout慢了一些。我们知道ViewGroup是没有onMeasure方法的,这个方法是交给子类自己实现的。因为不同的ViewGroup子类布局都不一样,那么onMeasure索性就全部交给他们自己实现好了。

下面通过源码分析一下:

1.1    RelativeLayout的onMeasure分析

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//...
View[] views = mSortedHorizontalChildren;
int count = views.length;
for (int i = 0; i < count; i++) {View child = views[i];if (child.getVisibility() != GONE) {LayoutParams params = (LayoutParams) child.getLayoutParams();applyHorizontalSizeRules(params, myWidth);measureChildHorizontal(child, params, myWidth, myHeight);if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {offsetHorizontalAxis = true;}}
}views = mSortedVerticalChildren;
count = views.length;
for (int i = 0; i < count; i++) {View child = views[i];if (child.getVisibility() != GONE) {LayoutParams params = (LayoutParams) child.getLayoutParams();applyVerticalSizeRules(params, myHeight);measureChild(child, params, myWidth, myHeight);if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {offsetVerticalAxis = true;}if (isWrapContentWidth) {width = Math.max(width, params.mRight);}if (isWrapContentHeight) {height = Math.max(height, params.mBottom);}if (child != ignore || verticalGravity) {left = Math.min(left, params.mLeft - params.leftMargin);top = Math.min(top, params.mTop - params.topMargin);}if (child != ignore || horizontalGravity) {right = Math.max(right, params.mRight + params.rightMargin);bottom = Math.max(bottom, params.mBottom + params.bottomMargin);}}}//...
}

根据源码我们发现RelativeLayout会根据2次排列的结果对子View各做一次measure。这是为什么呢?首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,而这个依赖关系可能和Xml布局中View的顺序不同,在确定每个子View的位置的时候,需要先给所有的子View排序一下。又因为RelativeLayout允许ViewB在横向上依赖ViewA,ViewA在纵向上依赖B。所以需要横向纵向分别进行一次排序测量。

同时需要注意的是View.measure()方法存在以下优化:

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||widthMeasureSpec != mOldWidthMeasureSpec ||heightMeasureSpec != mOldHeightMeasureSpec) {...mOldWidthMeasureSpec = widthMeasureSpec;mOldHeightMeasureSpec = heightMeasureSpec;
}

即如果我们或者我们的子View没有要求强制刷新,而父View给子View传入的值也没有变化(也就是说子View的位置没变化),就不会做无谓的测量。RelativeLayout在onMeasure中做横向测量时,纵向的测量结果尚未完成,只好暂时使用myHeight传入子View系统。这样会导致在子View的高度和RelativeLayout的高度不相同时(设置了Margin),上述优化会失效,在View系统足够复杂时,效率问题就会很明显。

1.2  LinearLayoutonMeasure过程

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  if (mOrientation == VERTICAL) {  measureVertical(widthMeasureSpec, heightMeasureSpec);  } else {  measureHorizontal(widthMeasureSpec, heightMeasureSpec);  }
}
//LinearLayout会先做一个简单横纵方向判断,我们选择纵向这种情况继续分析
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
//...
for (int i = 0; i < count; ++i) {  final View child = getVirtualChildAt(i);  //... child为空、Gone以及分界线的情况略去//累计权重LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();  totalWeight += lp.weight;  //计算if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {  //精确模式的情况下,子控件layout_height=0dp且weight大于0无法计算子控件的高度//但是可以先把margin值合入到总值中,后面根据剩余空间及权值再重新计算对应的高度final int totalLength = mTotalLength;  mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);  } else {  if (lp.height == 0 && lp.weight > 0) {  //如果这个条件成立,就代表 heightMode不是精确测量以及wrap_conent模式//也就是说布局是越小越好,你还想利用权值多分剩余空间是不可能的,只设为wrap_content模式lp.height = LayoutParams.WRAP_CONTENT;  }  // 子控件测量measureChildBeforeLayout(child, i, widthMeasureSpec,0, heightMeasureSpec,totalWeight== 0 ? mTotalLength :0);         //获取该子视图最终的高度,并将这个高度添加到mTotalLength中final int childHeight = child.getMeasuredHeight();  final int totalLength = mTotalLength;  mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); } //...
}

源码中已经标注了一些注释,需要注意的是在每次对child测量完毕后,都会调用child.getMeasuredHeight()获取该子视图最终的高度,并将这个高度添加到mTotalLength中。但是getMeasuredHeight暂时避开了lp.weight>0且高度为0子View,因为后面会将把剩余高度按weight分配给相应的子View。因此可以得出以下结论:

(1)如果我们在LinearLayout中不使用weight属性,将只进行一次measure的过程。

(2)如果使用了weight属性,LinearLayout在第一次测量时获取所有子View的高度,之后再将剩余高度根据weight加到weight>0的子View上。

由此可见,weight属性对性能是有影响的。

3.   总结论

(1)RelativeLayout慢于LinearLayout是因为它会让子View调用2次measure过程,而LinearLayout只需一次,但是有weight属性存在时,LinearLayout也需要两次measure。

(2)RelativeLayout的子View如果高度和RelativeLayout不同,会导致RelativeLayout在onMeasure()方法中做横向测量时,纵向的测量结果尚未完成,只好暂时使用自己的高度传入子View系统。而父View给子View传入的值也没有变化就不会做无谓的测量的优化会失效,解决办法就是可以使用padding代替margin以优化此问题。

(3)在不响应层级深度的情况下,使用Linearlayout而不是RelativeLayout。

结论中的第三条也解释了文章前言中的问题:DecorView的层级深度已知且固定的,上面一个标题栏,下面一个内容栏,采用RelativeLayout并不会降低层级深度,因此这种情况下使用LinearLayout效率更高。

上面已经将的很清楚了,在层数相同的情况下,使用LinearLayout作为根布局,在复杂布局时,使用RelativeLayout减少界面的层数。

Android RelativeLayout和LinearLayout性能分析就讲完了。

就这么简单。



Android RelativeLayout和LinearLayout性能分析相关推荐

  1. RelativeLayout和LinearLayout性能比较

    RelativeLayout和LinearLayout性能比较 相对布局和线性布局的性能比较 [转载请注明出处] :http://blog.csdn.net/guyuealian/article/de ...

  2. Android Studio CPU profiler性能分析工具介绍和使用详解

    Android Studio CPU profiler性能分析工具介绍和使用详解 CPU profiler介绍 Android Studio CPU 性能剖析器可实时检查应用的 CPU 使用率和线程活 ...

  3. Android app native代码性能分析

    分析我们app中native层的C/C++代码性能,能够方便我们找出其中的性能瓶颈,并在稍后做有针对性的优化. 下载android-ndk-profiler 工欲善其事,必先利其器,我们先要有良好的工 ...

  4. Android开发之——Profiler-CPU性能分析

    一 Profiler-CPU能做什么 优化应用的 CPU 使用率能带来诸多好处,如提供更快.更顺畅的用户体验,以及延长设备电池续航时间 可以使用 CPU 性能剖析器在与应用交互时实时检查应用的 CPU ...

  5. 【转】RelativeLayout和LinearLayout及FrameLayout性能分析

    原文:http://blog.csdn.net/hejjunlin/article/details/51159419 工作一段时间后,经常会被领导说,你这个进入速度太慢了,竞品的进入速度很快,你搞下优 ...

  6. Android系统性能优化(54)---Android性能分析专题

    Android性能分析专题 1.  背景:Android App优化, 要怎么做? 2.  Android App优化之性能分析工具 3.  Android App优化之提升你的App启动速度之理论基 ...

  7. 性能分析工具 之 Perfetto基本使用

    Perfetto是google从Android10开始引入的一个全新的平台级跟踪分析工具.适用于Android.Linux和Chrome的更加通用和复杂的用于性能检测和跟踪分析的生产级开源项目.在an ...

  8. LinearLayout和RelativeLayout属性和性能详解

    一.前期基础知识储备 上,官方文档 由上面的官方文档,我们可以看出,两个布局方式的相同,都是继承自View.Group,是一种容器控件,LinearLayout的布局层次比较简单,方向和位置都比较容易 ...

  9. 正确使用 Android 性能分析工具——TraceView

    前面唠叨 最近公司app中有些列表在滑动的时候会有卡顿现象,我就开始着手解决这些问题,解决问题之前首先要分析列表滑动的性能瓶颈在什么地方.因为之前不会正确使用TraceView这个工具,主要是看不懂T ...

最新文章

  1. Java JDK 学习笔记:File类
  2. Hacking PostgreSQL
  3. phpcms v9 index.php,【转】phpcms v9中tags列表页url用拼音作为路径的方法
  4. cas 4.2.7 官方手册_海城市地区,保险手册核验的简单流程
  5. 实现打印异常日志_老生常谈SpringAop日志收集与处理做的工具包
  6. POJ1426-Find The Multiple(DFS)
  7. 【Python】Pandas加载并查询Excel文件
  8. 什么样的人最适合创业?
  9. the android emulator process,Android studio报错:The emulator process for AVD (xxx) was killed
  10. python zip函数_Python zip()函数
  11. Hive实现oracle的Minus函数
  12. 同样是编译jogl,不同平台的编译速度相差几十倍?
  13. 人脸识别系统 讲解以及环境搭建(Java 附源码)
  14. vue动态创建三级导航
  15. scara机器人运动学正逆解
  16. 软件工程实验报告1-可行性分析
  17. 如何定位到服务器CPU飙高的原因
  18. SX1278调试记录
  19. “非主流”数据库合集,简介
  20. 【知识星球】视频分类模型和数据集板块汇总介绍

热门文章

  1. Jmeter测试监控 Summary Report界面
  2. JQuery-让Ajax变的更简单
  3. TroubleshootingGuide for JavaTM SE 6withHotSpot TM VM (翻译附录未完待续)-2
  4. 检测是否是手机访问接口
  5. CentOS配置Lamp
  6. python 行列式计算
  7. Guava Cache探索及spring项目整合GuavaCache实例
  8. Java 成员变量和局部变量
  9. mysql中文显示问号
  10. c# in deep 之Lambda表达式