美文网首页ui布局
RelativeLayout 和 LinearLayout 性能

RelativeLayout 和 LinearLayout 性能

作者: WaterYuan | 来源:发表于2019-05-10 16:57 被阅读0次
    层级数相同时LinearLayout性能优于RelativeLayout,
    但相对于LinearLayout,RelativeLayout一般能减少层级数从而优化整体性能
    

    RelativeLayout和LinearLayout性能比较

    RelativeLayout和LinearLayout是Android中常用的布局,两者的使用会极大的影响程序生成每一帧的性能,因此,正确的使用它们是提升程序性能的重要工作。记得以前,较低的SDK版本新建Android项目时,默认的布局文件是采用线性布局LinearLayout,但现在自动生成的布局文件都是RelativeLayout,或许你会认为这是IDE的默认设置问题,其实不然,这由 android-sdk\tools\templates\activities\BlankActivity\root\res\layout\activity_simple.xml.ftl 这个文件事先就定好了的,也就是说这是Google的选择,而非IDE的选择。那SDK为什么会默认给开发者新建一个默认的RelativeLayout布局呢?

    当然是因为RelativeLayout的性能更优,性能至上嘛。但是我们再看看默认新建的这个RelativeLayout的父容器,也就是当前窗口的顶级View——DecorView,它却是个垂直方向的LinearLayout,上面是标题栏,下面是内容栏。那么问题来了,Google为什么给开发者默认新建了个RelativeLayout,而自己却偷偷用了个LinearLayout,到底谁的性能更高,开发者该怎么选择呢?

    一、View的一些基本工作原理
    先通过几个问题,简单的了解写android中View的工作原理吧。
    (1)View是什么?
    简单来说,View是Android系统在屏幕上的视觉呈现,也就是说你在手机屏幕上看到的东西都是View。
    (2)View是怎么绘制出来的?
    View的绘制流程是从ViewRoot的performTraversals()方法开始,依次经过measure(),layout()和draw()三个过程才最终将一个View绘制出来。
    (3)View是怎么呈现在界面上的?
    Android中的视图都是通过Window来呈现的,不管Activity、Dialog还是Toast它们都有一个Window,然后通过WindowManager来管理View。Window和顶级View——DecorView的通信是依赖ViewRoot完成的。

    View的绘制,从ViewRoot的performTraversals()方法开始依次调用perfromMeasure、performLayout和performDraw这三个方法。这三个方法分别完成顶级View的measure、layout和draw三大流程,其中perfromMeasure会调用measure,measure又会调用onMeasure,在onMeasure方法中则会对所有子元素进行measure,这个时候measure流程就从父容器传递到子元素中了,这样就完成了一次measure过程,接着子元素会重复父容器的measure,如此反复就完成了整个View树的遍历。同理,performLayout和performDraw也分别完成perfromMeasure类似的流程。通过这三大流程,分别遍历整棵View树,就实现了Measure,Layout,Draw这一过程,View就绘制出来了。

    二、RelativeLayout和LinearLayout性能PK
    分别来追踪下RelativeLayout和LinearLayout这三大流程的执行耗时。
    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慢了一大截。
    (1)RelativeLayout的onMeasure()方法
    RelativeLayout分别对所有子View进行两次measure,横向纵向分别进行一次,这是为什么呢?首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,而这个依赖关系可能和布局中View的顺序并不相同,在确定每个子View的位置的时候,需要先给所有的子View排序一下。又因为RelativeLayout允许A,B 2个子View,横向上B依赖A,纵向上A依赖B。所以需要横向纵向分别进行一次排序测量。mSortedHorizontalChildren和mSortedVerticalChildren是分别对水平方向的子控件和垂直方向的子控件进行排序后的View数组。
    (2)LinearLayout的onMeasure()方法
    与RelativeLayout相比LinearLayout的measure就简单的多,只需判断线性布局是水平布局还是垂直布局即可,然后才进行测量

    如果不使用weight属性,LinearLayout会在当前方向上进行一次measure的过程,如果使用weight属性,LinearLayout会避开设置过weight属性的view做第一次measure,完了再对设置过weight属性的view做第二次measure。由此可见,weight属性对性能是有影响的,而且本身有大坑,请注意避让。

    三、小结
    从源码中我们似乎能看出,我们先前的测试结果中RelativeLayout不如LinearLayout快的根本原因是RelativeLayout需要对其子View进行两次measure过程。而LinearLayout则只需一次measure过程,所以显然会快于RelativeLayout,但是如果LinearLayout中有weight属性,则也需要进行两次measure,但即便如此,应该仍然会比RelativeLayout的情况好一点。 RelativeLayout另一个性能问题 对比到这里就结束了嘛?显然没有!我们再看看View的Measure()方法都干了些什么?

    View的measure方法里对绘制过程做了一个优化,如果我们或者我们的子View没有要求强制刷新,而父View给子View的传入值也没有变化(也就是说子View的位置没变化),就不会做无谓的measure。但是上面已经说了RelativeLayout要做两次measure,而在做横向的测量时,纵向的测量结果尚未完成,只好暂时使用myHeight传入子View系统,假如子View的Height不等于(设置了margin)myHeight的高度,那么measure中上面代码所做得优化将不起作用,这一过程将进一步影响RelativeLayout的绘制性能。而LinearLayout则无这方面的担忧。解决这个问题也很好办,如果可以,尽量使用padding代替margin。

    结论
    (1)RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View 2次onMeasure
    (2)RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
    (3)在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
    (4)提高绘制性能的使用方式
    根据上面源码的分析,RelativeLayout将对所有的子View进行两次measure,而LinearLayout在使用weight属性进行布局时也会对子View进行两次measure,如果他们位于整个View树的顶端时并可能进行多层的嵌套时,位于底层的View将会进行大量的measure操作,大大降低程序性能。因此,应尽量将RelativeLayout和LinearLayout置于View树的底层,并减少嵌套。

    最后思考一下文章开头的疑问:较低的SDK版本新建Android项目时,默认的布局文件是采用线性布局LinearLayout,但现在自动生成的布局文件都是RelativeLayout,为什么呢?
    RelativeLayout 在性能上更好,因为在诸如 ListView 等控件中,使用 LinearLayout 容易产生多层嵌套的布局结构,这在性能上是不好的。而 RelativeLayout 因其原理上的灵活性,通常层级结构都比较扁平,很多使用LinearLayout 的情况都可以用一个 RelativeLayout 来替代,以降低布局的嵌套层级,优化性能。所以从这一点来看,Google比较推荐开发者使用RelativeLayout,因此就将其作为Blank Activity的默认布局了。


    参考:
    https://blog.csdn.net/guyuealian/article/details/52162774
    https://www.jianshu.com/p/8a7d059da746
    http://www.cnblogs.com/hellsong/p/4613426.html?utm_source=tuicool&utm_medium=referral

    相关文章

      网友评论

        本文标题:RelativeLayout 和 LinearLayout 性能

        本文链接:https://www.haomeiwen.com/subject/esuioqtx.html