性能探究之onMeasure

虽然如今RecycleView大行其道,但作为老牌控件listview仍应用广泛,但真正使用时,由于业务上的需求以及开发人员的理解不深入,使得listview性能并不十分高,造成卡顿

那么先从以下几点进行测试

  • 父布局类型(相对,线性)
  • 布局嵌套深度

XML布局代码



    

根布局LinearLayout,再嵌套3层LinearLayout,内置一个自定义Listview,自定义Listview的代码很简单,只是单纯在onMeasure打印一段话

public class TestListView extends ListView {
    private static final String TAG = "TestListView";

    public TestListView(Context context) {
        super(context);
    }

    public TestListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TestListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d(TAG, "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

先看LinearLayout多层嵌套下的效果

性能探究之onMeasure_第1张图片
LinearLayout_listview.jpg线性布局嵌套测试——无权重.gif
  • 可以见到的是在LinearLayout嵌套了3层的情况下,进入界面初始化调用了2次onMeasure()
  • 让与listview同层级的imageview消失(GONE)后,不会间接触发listview调用onMeasure
  • 让listview里的item图片visible或者gone,会同样的让listview调用一个onMeasure

那么给ListView设置权重以后再看效果


性能探究之onMeasure_第2张图片
LinearLayout_listview.jpg线性布局嵌套测试——有权重.gif
  • 和前者的不同之处在于设置了权重以后,listview同级的imageview设置visible和gone后,会间接让listview重新调用onMeasure来重新计算listview的高度

再来看看RelativeLayout多层嵌套下的效果

性能探究之onMeasure_第3张图片
RelativeLayout_listview.jpg相对布局嵌套测试.gif
  • 可以见到的是在RelativeLayout嵌套了3层的情况下,进入界面初始化调用了16次onMeasure() ,即2^4
  • 让与listview同层级的imageview消失(GONE)后,会间接触发listview调用8次onMeasure,即2^3
  • 让listview里的item图片visible或者gone,会同样的让listview调用8次onMeasure,即2^3

因RelativeLayout的特殊性,功能的丰富性同时导致了其性能的低下,在界面初始化时需调用两次onMeasure(),而RelativeLayout内部的onMeasure方法更是需要遍历子view,分别横向和纵向测量子view

那么我们可以得出一个结论,在能实现需求和功能的前提下,基础布局尽量不选择RelativeLayout,特别是ListView在RelativeLayout的嵌套下,多次调用onMeasure(),而ListView又在onMeasure调用了getView,大部分的逻辑在getView中,指数次调用必然导致性能的大幅下降

参考资料

Android应用性能优化系列视图篇——三大基础布局性能比较
Android应用性能优化系列视图篇——ListView自适应导致的严重性能问题
Android源码(这个就自己进布局源码看吧)

你可能感兴趣的:(性能探究之onMeasure)