ListView优化详解

一、为什么需要优化?

  • ListView这个控件使用的场景很多,常用于向用户展示大量数据(如通讯录,新闻资讯等)。当它需要加载大量数据时,会占据大量内存,影响性能,这时候就需要对ListView进行一些相关优化了。


二、ListView优化的核心-View的复用

  • 这里需要先对Adapter的getView有所了解,Adapter是数据和控件的中间媒介,它们的关系如下图所示:


  • 一般我们通过继承BaseAdapter来实现我们自己的Adapter,一般建议在Activity里作为内部类实现(便于传递数据等)。
  • 在ListView开始绘制之前,先调用getCount()方法返回要在ListView上显示的Item数量,然后ListView根据此数据开始调用getView方法绘制每一行。
  1. GetView方法中有三个参数position标识ListView正绘制第几个Item。
  2. convertView相当于View控件的缓存装置,通过LayoutInflater可将Item的布局文件压缩成一个视图赋值给convertView,最后convertView返回给ListView进行绘制。


  • ListView中有许多Item,ListView滑动时会重绘Item,如果每次都对convertView都要重新赋值,对Item布局里的每个控件重新绑定(findViewById,是一个树查找过程,耗时的操作)则会花费大量不必要的时间,而且内存空间也会消耗很大,因此有了下面两种主要的优化方法。


三、ListView优化的主要方法

  1. convertView重用

  • 在一个完整的ListView第一次出现时,每个Item为Null,convertView也为Null,ListView创建的Item数量刚好充满屏幕为止。假设屏幕最多显示7个Item,当ListView滑动时,旧Item滑进,新Item滑出,在程序内部的实现过程如下图:


  • 当Item1滑出,Item8滑入,converView将之前滑出的视图信息记录下来,新Item滑进来,若他们用的是同种xml布局文件压缩成的view视图,就不用重新inflate,可以直接复用,只用将数据更新一下就行了。

      2、利用ViewHolder避免反复实例化控件

  • 同理,数据更新时需要通过findViewById绑定相应控件更新数据,这里为了再次优化,可以为每一个视图绑定一个ViewHolder对象,当ListView完成第一次绘制时,convertView通过使用setTag()方法,使得每个Item的View携带一个查找完成的ViewHolder对象(里面存好了对应的控件)。当convertView不为null时(即滑动开始),且在重复利用之前创建好的视图时,使用getTag()方法获取绑定的ViewHolder对象,快速定位到控件。
  • 示例代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    String jpg_path=(String)getItem(position);
   
ViewHolder viewHolder=null;
    if
(convertView==null){
        convertView= LayoutInflater.from(context).inflate(R.layout.jpg_item,null);
       
viewHolder=new ViewHolder();
       
viewHolder.jpg_name=(TextView)convertView.findViewById(R.id.jpg_name);
       
viewHolder.jpg=(ImageView)convertView.findViewById(R.id.jpg);
       
convertView.setTag(viewHolder);
   
}
    else{
        viewHolder=(ViewHolder)convertView.getTag();
   
}
    viewHolder.jpg_name.setText(jpg_path);
   
Log.e("HELLO",jpg_path);
    if
(idle) {
        imageLoader.bindBitmap(jpg_path, viewHolder.jpg, 100, 100);
   
}
    else{ viewHolder.jpg.setImageDrawable(context.getResources().getDrawable(R.drawable.image_default));}
    return convertView;
}




class ViewHolder{
    private TextView jpg_name;
    private
ImageView jpg;
}


四、ListView优化的其它方面:

  1. 尽量让ItemView的Layout层次结构简单,这是所有Layout都必须遵循的。
  2. getView()中尽量少做其它事情,不要有耗时操作,可以考虑滑动时不要加载图片。
  3. 当ListView中有几个不同类型的Item,从而需要创建不同的View,这时要利用好getItemViewType来复用View,但注意Item的类型不要太多。


五、后记:

  • 在用ListView显示不同类型Item的时候要注意一个小问题,就是getViewTypeCount()返回的int值要比定义的所有Type的int值大,否则会出现java.lang.ArrayIndexOutOfBoundsException。
  • 代码如下:

private final int TYPE1 = 0;
private final int TYPE2 = 1;
private final int TYPE3 = 2;

@Override
public int getViewTypeCount() {
   
return TYPE3+1;
}

  • 最后贴一张运行的效果图:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值