虽然如今RecycleView大行其道,但作为老牌控件listview仍应用广泛,但真正使用时,由于业务上的需求以及开发人员的理解不深入,使得listview性能并不十分高,造成卡顿
那么先从以下几点进行测试
- 父布局类型(相对,线性)
- 布局嵌套深度
XML布局代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="添加数据"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onToggle"
android:text="显示/隐藏"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<com.hhwant.speed.app.TestListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="200dp"
>
</com.hhwant.speed.app.TestListView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
根布局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多层嵌套下的效果
- 可以见到的是在LinearLayout嵌套了3层的情况下,进入界面初始化调用了2次onMeasure()
- 让与listview同层级的imageview消失(GONE)后,不会间接触发listview调用onMeasure
- 让listview里的item图片visible或者gone,会同样的让listview调用一个onMeasure
那么给ListView设置权重以后再看效果
- 和前者的不同之处在于设置了权重以后,listview同级的imageview设置visible和gone后,会间接让listview重新调用onMeasure来重新计算listview的高度
再来看看RelativeLayout多层嵌套下的效果
- 可以见到的是在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源码(这个就自己进布局源码看吧)