分析之前先了解下View的绘制流程

首先view在windows中的布局样式如下图:

Relativelayout和LinearLayout对比分析-LMLPHP

view绘制在windows,windows与DecoverView的交互在VIewRoot中进行。

view绘制的入口函数是ViewRootImpl中的performTraversals, performTraversals钟会一次调用performMeasure、performLayout、performDraw,三个函数中会分别调用view.Measure、view.Layout、view.Draw,然后分别调用需要子类实现的onMeasure、onLayout、onDraw函数。

而继承自view的自定义view或者系统写好的textview或者LinearLayout等实例化的onMeasure、onLayout、onDraw函数分别用于测量view大小,摆放view、以及将view画出来。

LinearLayout继承自viewGroup,在onMeasure中,会分别调用子控件的view.Measure, 进而在子控件的onMeasur中完成测量,如果子控件仍然是一个viewGroup则依次下去。

view绘制各重载函数的执行流程:

      1、android:visibility=visible

2、android:visibility=invisible

3、android:visibility=gone

下面比较下LinearLayout和RelativeLayout的性能

一个实现垂直列表的布局测试数据如下:

LinearLayout

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

RelativeLayout

Measure:2.280ms
Layout:0.153ms
draw:7.696ms

考虑到误差,两者layout和draw几乎差不多,主要区别在于Measure。

1、分析源码发现,在RelativeLayout中,由于布局可以是B横向依赖A,A横向依赖B, 所以,Measure中会被Measure两次,一次是横向的Measure,一次是纵向。

而在LinearLayout中,在测量之前就判断了是横向还是纵向布局。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOrientation == VERTICAL) {
measureVertical(widthMeasureSpec, heightMeasureSpec);
} else {
measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
}

2、但是在Linearlayout中如果设置weight会影响性能,因为LinearLayout会避开设置过weight属性的view做第一次measure,完了再对设置过weight属性的view做第二次measure。

3、view中的Measure有个优化,但是如果RelativeLayout中设置的margin就会跳过这个优化,多以尽量使用padding而不是margin。

4、

.在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最后再思考一下文章开头那个矛盾的问题,为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。

参考:
作者:尹star
链接:http://www.jianshu.com/p/8a7d059da746

作者:周君宜
链接:http://www.jianshu.com/p/08e6dab7886e
04-30 19:48