bindView中switch-case性能问题:ListView图片加载卡顿解决方案咨询
解决ListView卡顿:把CursorAdapter bindView中的逻辑外移
嘿,这个问题我太熟了——bindView会随着ListView的滑动被频繁调用,里面的switch-case如果分支多或者涉及数据库相关的判断,必然会拖慢UI线程,导致滑动卡顿。当然可以把数据库比较逻辑“外移”,这里给你几个实用的方案:
方案1:直接在数据库中存储图片标识(最优解)
这是最彻底的解决办法,把图片的映射逻辑从显示阶段提前到数据入库阶段。
- 给你的数据库表新增一个字段,比如
image_res_id(存储Drawable资源ID)或者image_path(存储本地图片路径)。 - 当你向数据库插入数据时,根据条目的类型直接把对应的图片资源ID/路径存入这个字段。
- 查询数据时,把这个字段一起查进Cursor,这样在
bindView()里就不用再做任何判断,直接拿值设置图片:
@Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); // 直接从Cursor取预存的图片ID,跳过switch-case int imageResId = cursor.getInt(cursor.getColumnIndex("image_res_id")); holder.imageView.setImageResource(imageResId); // 其他UI设置... }
这种方式完全消除了bindView中的重复逻辑,性能提升最明显,而且代码更简洁。
方案2:预处理映射关系,避免重复执行switch-case
如果暂时没法修改数据库结构,那就把switch-case的逻辑从bindView中移出来,只执行一次:
- 在CursorAdapter的初始化阶段(比如构造方法里,或者
changeCursor()方法中),遍历Cursor一次,把每个条目的ID和对应的图片资源ID存在一个映射集合里(比如HashMap<Long, Integer>)。 - 之后在bindView中,直接通过条目ID从映射集合里取图片ID,不用再做判断:
public class MyCursorAdapter extends CursorAdapter { private HashMap<Long, Integer> mItemImageMap; public MyCursorAdapter(Context context, Cursor c) { super(context, c, 0); preprocessImageMap(c); } @Override public void changeCursor(Cursor newCursor) { super.changeCursor(newCursor); preprocessImageMap(newCursor); } private void preprocessImageMap(Cursor cursor) { mItemImageMap = new HashMap<>(); if (cursor == null) return; cursor.moveToFirst(); do { long itemId = cursor.getLong(cursor.getColumnIndex("_id")); int type = cursor.getInt(cursor.getColumnIndex("type")); // 这里只执行一次switch-case int imageResId; switch (type) { case 1: imageResId = R.drawable.type1; break; case 2: imageResId = R.drawable.type2; break; // 其他类型分支... default: imageResId = R.drawable.default_image; } mItemImageMap.put(itemId, imageResId); } while (cursor.moveToNext()); // 把Cursor移回初始位置,避免影响后续查询 cursor.moveToPosition(-1); } @Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); long itemId = cursor.getLong(cursor.getColumnIndex("_id")); // 直接从映射集合取图片ID,无需重复判断 int imageResId = mItemImageMap.get(itemId); holder.imageView.setImageResource(imageResId); // 其他UI设置... } // ViewHolder实现... }
这样switch-case只会在Cursor更新时执行一次,而不是每次bindView都跑一遍,能显著减少UI线程的计算量。
额外优化:ViewHolder+图片加载优化
别忘了配合ViewHolder复用View,避免频繁创建和销毁View;如果你的图片是本地大资源或者网络图片,一定要用异步加载库来加载,避免阻塞UI线程:
// 用Glide加载本地资源的例子 Glide.with(context) .load(imageResId) .into(holder.imageView);
这样即使图片加载需要一点时间,也不会影响ListView的滑动流畅度。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

