大家好,首先,RelativeLayout和LinearLayout都是常用/通用布局方法,*二者都可以靠自己实现完整的页面实现*。而在平时使用中,由于两者各有所长,所以在某些时候需要对二者综合使用。
为了探讨二者性能区别,就不得不寻根究底:两种方法的实现都要靠’View‘s(ViewGroup)在屏幕上的视觉呈现,View再通过performTraversals(代码巨长,用于判断是否执行以下三种操作)-->->measure()-->layout()-->draw()一步一步绘制出来,所以measure等三个流程的耗时就成了此次研究的核心。(L:LinearLayout、R:RelativeLayout)
一、*两个‘onMeasure’的PK!*
需要先了解的是:measureChild/measureChildHoricontal/measureChildVertical直接受制于measure,所以开门见山直接分析measure函数:View的measure方法是final的,子类(L、R等方法)可以重写onMeasure。再深一步说,“measure”这一活动的实现要通过一个onMeasure方法对整个View树进行层层“渗透”(顶层父View对子View递归view.measure,measure再回调onMeasure),Layout和Draw也是类似的流程。
所以就看两个onMeasure的battle,我们先“蜻蜓点水”式看一下onMeasure在两方的源码片段,可以发现R方法对子View进行了两次遍历,因为R方法中排列方式大多是依赖关系,这些依赖关系在确定位置前要将子View排列一遍,而且R方法允许两个子View分别从纵、横两个方向依赖,所以便需要两个方向分别进行排序测量,当层级太深,measure | 指 | 数 | 爆 | 炸 | ;我截取的L方法的OnMeasure源码也是68行,不过有12行的注释,所以我单方面宣布L方法胜利~~--肯定还为时过早,L方法的实现也简洁明了,即先判断线性关系,然后执行对应方向的测量,这里便不细说了。
二、*场外加赛!*
L方法如果不使用Weight属性,L方法仅是一条路走到黑,一次measure,如果使用了Weight属性,就会在后面对其进行*第二次的measure*(但第二次相对简单,用时可能会比一次短)。R方法的measure函数中也藏了*彩蛋*——如果子View的位置没有变化,就不会做无用measure,以减少调用次数。可惜*彩蛋里有根骨头*——R方法的两个方向的遍历如果横向比纵向完成得快,会直接传myHeight入子系统,优化在margin不同于myHeight时不起作用,所以R方法对深层级很抵触。
三、*为啥不比Layout和Draw了?*
本来还打算对着Layout和Draw源码的冰山一角默背唐诗三百首,直至遇到大佬的1000次measure\layout\draw的不同布局耗时对比
*https://blog.csdn.net/a740169405/article/details/79037191*(结果如下图,单位ms越小越棒),我仿佛能听见大佬轻蔑的声音“屏幕前,龙不吟,虎不啸,小小书童可笑可笑”
虽然大佬的代码我复制过来也运行不了,不过我依然对这个结果很信服,原文总结中指出各种布局除了measure用时差别比较大外,layout和draw耗时差别不大。
综上:
1、不影响层级深度情况情况下,请直接淘汰R选手。
2、R两次measure,加上L也可能一次半/两次measure,如果他们在树干处,底层的View会受苦,所以尽量将他们放在树枝处,或者直接减少嵌套次数。
3、见2,减少嵌套次数就对了。
4、多层L嵌套时(复杂布局,有互相依赖最好),尽量使用R;简单已知布局直接使用L。
5、include、padding kill margin 等方法也可优化R方法。
6、有的大佬说开发者默认新建RelativeLayout是希望开发者能采用尽量少的View层级。我想也可能暗示R>L(逃
附录:
细致入微版三种流程解析:https://blog.csdn.net/yanbober/article/details/46128379
简版measure源码解析:https://blog.csdn.net/itachi85/article/details/50931348
简版layout\draw源码解析:https://blog.csdn.net/itachi85/article/details/50971964
四种基本布局简介:https://www.cnblogs.com/woider/p/5118742.html
以上