ListView性能优化

Posted evolutionoflicorice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ListView性能优化相关的知识,希望对你有一定的参考价值。

ListView在ScrollView中无法正确计算它的大小, 故不能显示正常的条目。

解决办法有:

1.重写ListView, 覆盖onMeasure()方法。

 1 public class WrapperListView extends ListView {
 2     public WrapperListView(Context context) {
 3         super(context);
 4     }
 5     public WrapperListView(Context context, AttributeSet attrs) {
 6         super(context, attrs);
 7     }
 8     public WrapperListView(Context context, AttributeSet attrs, int defStyleAttr) {
 9         super(context, attrs, defStyleAttr);
10     }
11     public WrapperListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
12         super(context, attrs, defStyleAttr, defStyleRes);
13     }
14     /**
15      * 重写该方法,达到使ListView适应ScrollView的效果
16      */
17     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
18         int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
19         super.onMeasure(widthMeasureSpec, expandSpec);
20     }
21 }

2.动态设置LIstView的高度,不需要重写LIstView

只需要在setAdapter之后调用如下方法即可:

public void setListViewHeightBasedOnChildren(ListView listView) {
        // 获取ListView对应的Adapter
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            return;
        }
        int totalHeight = 0;
        for (int i = 0, len = listAdapter.getCount(); i < len; i++) {
            // listAdapter.getCount()返回数据项的数目
            View listItem = listAdapter.getView(i, null, listView);
            // 计算子项View 的宽高
            listItem.measure(0, 0);
            // 统计所有子项的总高度
            totalHeight += listItem.getMeasuredHeight();
        }
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        // listView.getDividerHeight()获取子项间分隔符占用的高度
        // params.height最后得到整个ListView完整显示需要的高度
        listView.setLayoutParams(params);
    }

另外,这时,这时最好给ListView之外嵌套一层LinearLayout,不然有时候这种方法会失效。

最后,尽量避免ScrollView嵌套Listview,可使用使用listview的addHeader() 函数来实现预期效果或者利用布局的特性达到预期效果。

 

ListView就是一个将数据集合以动态滚动的方式展示到用户界面的View

ListView的父类AbsListView中的内部类RecycleBin(防止ListView出现oom)

优化:

1. getview中的convertView中起到缓存作用,复用convertView,对convertView进行判空,为空则初始化,从而减少了很多不必要的View的创建、减少findViewById的次数

2.采用ViewHolder模式缓存item条目的引用,减少多次findViewByID的次数

3.避免在getView方法中做耗时操作

3.给listView设置滚动监听器 根据不同状态 不同处理数据 分批分页加载 根据listView的状态去操作,比如当列表快速滑动时不去开启大量的异步任务去请求图片

4.listview每个item层级结构不要太复杂
5.listview每个item中异步加载图片,并对图片加载做优化,(关于Listview分页加载和图片异步加载思路请看接下来的文章内容)
6.尽量能保证 Adapter 的 hasStableIds() 返回 true 这样在 notifyDataSetChanged() 的时候,如果item内容并没有变化,ListView 将不会重新绘制这个 View,达到优化的目的
7.在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。 由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现。
8.使用 RecycleView 代替listview: 每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善
9.ListView 中元素避免半透明: 半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。
Listview的一些相关拓展
1. 打开套有 ListVew的 ScrollView的页面布局默认起始位置不是最顶部
解决办法有两种:
方法一:把套在里面的ListVew 不让获取焦点即可。listview.setFocusable(false);注意:在xml布局里面设置android:focusable=“false”不生效
方法二:myScrollView.smoothScrollTo(0,0);
 
2.上拉加载和下拉刷新怎么实现

1.继承自LIstView实现OnScrollListener
实现OnScrollListener 接口重写onScrollStateChanged 和onScroll方法,
使用onscroll方法实现”滑动“后处理检查是否还有新的记录,如果有,调用 addFooterView,添加记录到adapter, adapter调notifyDataSetChanged 更新数据;如果没有记录了,把自定义的mFooterView去掉。使用onScrollStateChanged可以检测是否滚到最后一行且停止滚动然后执行加载

2.头部和尾部都是单独的两个继承自LinearLayout布局,通过LIstView的addHeaderView()和addFooterView()两个方法把其加载到LIstView中
3.必须实现3个构造方法,每个方法都要实现initView()
4.Visibility实现头部和底部布局显示与隐藏

3.Listview里有Button就点不动了你知道吗

当ListView的Item中包含button,item点击事件与Button控件(button换成TextView不会冲突)点击冲突解决办法
1.不再对item进行监听,而是在adapter中监听整个item布局convertView.setOnClickListener()实现item的点击事件
2.在item的布局文件中给button设置属性android:focusable="false"以防button抢占listview的点击

4.ListView图片异步加载实现思路

1.先从内存缓存中获取图片显示(内存缓冲)
2.获取不到的话从SD卡里获取(SD卡缓冲,,从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅)
3.都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)

5.ViewHolder内部类非得要声明成static

这不是Android的优化,而是Java提倡的优化,
如果声明成员类不要求访问外围实例,就要始终把static修饰符放在它的声明中,使它成为静态成员类,而不是非静态成员类。
因为非静态成员类的实例会包含一个额外的指向外围对象的引用,保存这份引用要消耗时间和空间,并且导致外围类实例符合垃圾回收时仍然被保留。如果没有外围实例的情况下,也需要分配实例,就不能使用非静态成员类,因为非静态成员类的实例必须要有一个外围实例。
















以上是关于ListView性能优化的主要内容,如果未能解决你的问题,请参考以下文章

Android性能优化之提高ListView性能的技巧

《Android开发艺术探索》之Android性能优化ListView和RecyclerView(十七)

ListView性能优化——convertView&viewHolder

ListView性能优化

listview加载性能优化ViewHolder

Android性能优化之ListView缓存机制