ListView创建时其会创建屏幕可容纳数量的 Item,ListView 滚动时,刚消失的 item 会被保存到回收池中,新出现的 item 从回收池中获取避免重复创建,这个回收池由 ListView 维护。从回收池取出 item 会传递给 Adapter 的 getView() 方法的第二个参数,如果回收池中没有内容就传递一个 null。所以在 getView() 方法中如果第二个参数不为 null,就不要创建新的 ListView Item了,这可以极大的提高 ListView 性能。
public void getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
// 创建新的 ListView item
view = LayoutInflator.from(mContext).inflate(...);
}
/* 更新 ListView Item */
TextView textView = (TextView)view.findViewById(R.id.textview);
textView.setText("new data");
return view;
}
使用上面重用 ListView Item 的方法已经可以大幅提高 ListView 的效率了,但还存在一些可以改进的地方,上面每次更新 ListView Item 数据时,都要通过 View 的 findViewById() 方法定位每个子控件, findViewById() 会沿着ListView Item 的控件布局结构遍历每个控件直到找到指定 id 的控件,这是比较耗时的,尤其是布局比较复杂时。优化方法很简单,在每次创建新的 ListView Item 时保存通过 findViewById() 找到的每个子控件的引用。这些控件引用可以保存在一个单独的对象中,一般命名为 ViewHolder,然后将 ViewHolder 对象存储在 ListView item 中(通过 View 的 setTag() 方法,该方法可以在 View 中存储额外数据),下次可以直接从 ListView item 中取得。
public void getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
// 创建新的 ListView item
view = LayoutInflator.from(mContext).inflate(...);
// 保存控件引用在 ViewHolder 对象中
ViewHolder holder = new ViewHolder();
holder.textView = (TextView)view.findViewById(R.id.textview);
// 将 ViewHolder 对象保存在 ListView Item 中
view.setTag(holder);
}
/* 更新 ListView Item */
ViewHolder holder = (ViewHolder)view.getTag();
holder.textView.setText("new data");
return view;
}
private static class ViewHolder {
public TextView textView;
}
由于 ListView 高度或宽度不固定(布局参数中的宽或高指定为 wrap_content
),导致 ListView 重绘时需要重新计算 ListView Item 的大小,从而导致 getView() 方法重复调用。这对 ListView 的性能有显著的影响,解决办法就是指定 ListView 布局参数中的高和宽为固定大小或 match_parent
。
当 ListView Item 中包含图片控件时, 在 getView() 中更新数据一般是根据图片的 URI 取得 Bitmap 然后设置图片,如果 ImageView 显示的图片地址和要更新的图片地址相同,就完全没有必要做更新操作。可以采用和 ViewHolder 相同的方式,将图片的 URI 地址保存在 ImageView 的 tag 中,每次更新 ImageView 时先判断图片地址是否发生变化,只有发生变化时采取获取新的 Bitmap 更新。
String newImgUrl = ...;
String imgUrl = (String)imageView.getTag();
if (imageUrl == null || !imageUrl.equal(newImgUrl)) {
// 请求 newImgUrl 对应的图片
Bitmap bitmap = ...;
imageView.setImageBitmap(bitmap);
imageView.setTag(newImgUrl);
}
ListView 默认的滚动速度是比较快的,如果 ListView 滚动速度慢一点,那么每个 ListView Item 就有更多的加载时间,这也可以使 ListView 看上去更加流畅。下面代码将 ListView 的滚动速度减慢为原来的 1/10:
listview.setFriction(ViewConfiguration.getScrollFriction() * 10);
原文地址:http://blog.csdn.net/xiaohui_hubei/article/details/46382911