CursorAdapter加载图片出现错位混乱问题求助
嘿,我看了你的代码和问题描述,图片错位混乱的情况其实是ListView的item复用机制和你自己写的AsyncTask异步加载逻辑冲突导致的,我给你两个解决方案,先讲最直接的修复方法,再给你更省心的推荐方案~
解决CursorAdapter中图片加载错位的问题
问题根源
当ListView滚动时,会复用已经滑出屏幕的item视图。你的HttpRequestImageLoadTask是异步执行的,当图片加载完成时,原来的ImageView可能已经被用来展示另一个列表项的数据了,这时候直接设置图片就会导致错位。
方案1:给ImageView添加Tag验证(快速修复)
这是最直接的修复方式,通过给ImageView绑定当前要加载的图片标识,在异步任务完成后验证标识是否匹配,再设置图片。
修改RestaurantListActivityCursorAdapter的bindView方法
在启动图片加载任务前,给ImageView设置Tag绑定当前图片名称,同时先清空旧图片避免残留:
// Img ImageView listViewImage = (ImageView) view.findViewById(R.id.listViewImage); // 先清空旧图片,也可以设置一个默认占位图提升体验 listViewImage.setImageDrawable(null); if(getImage != null && !getImage.equals("")) { // 给ImageView设置Tag,绑定当前要加载的图片名称 listViewImage.setTag(getImage); String destinationPath = android.os.Environment.getExternalStorageDirectory().getPath()+ File.separatorChar+"/Android/data/com.nettport.restaurants/imgs"; File file = new File (destinationPath, getImage); if (file.exists ()){ Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); listViewImage.setImageBitmap(myBitmap); } else { String loadImage = websiteURL + "/_cache/" + getImage; new HttpRequestImageLoadTask(context, loadImage, listViewImage, getImage,"imgs").execute(); } }
修改HttpRequestImageLoadTask的onPostExecute方法
在设置图片前,检查ImageView的Tag是否和当前加载的图片名称一致,只有匹配时才设置图片:
@Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); if(imageView != null && result != null) { // 验证Tag是否匹配,避免错位到其他item if(imageName.equals(imageView.getTag())) { imageView.setImageBitmap(result); } } else { if(linearLayout != null && result != null){ BitmapDrawable background = new BitmapDrawable(resources, result); linearLayout.setBackground(background); } } }
方案2:使用成熟的图片加载库(推荐长期方案)
自己实现图片加载不仅容易遇到复用问题,还需要处理缓存、线程池、内存管理等诸多细节。推荐使用Glide、Picasso这类成熟的图片加载库,它们已经内置了对ListView/RecyclerView复用的处理,代码也更简洁:
比如用Glide的话,你的bindView里的图片加载逻辑可以简化成:
ImageView listViewImage = (ImageView) view.findViewById(R.id.listViewImage); if(getImage != null && !getImage.equals("")) { String imageUrl = websiteURL + "/_cache/" + getImage; // 本地缓存路径 File localFile = new File(android.os.Environment.getExternalStorageDirectory().getPath()+ File.separatorChar+"/Android/data/com.nettport.restaurants/imgs", getImage); if(localFile.exists()){ Glide.with(context).load(localFile).into(listViewImage); } else { Glide.with(context) .load(imageUrl) .diskCacheStrategy(DiskCacheStrategy.NONE) // 因为你自己管理本地缓存,可根据需要调整 .into(listViewImage); } } else { listViewImage.setImageDrawable(null); }
这样不仅解决了错位问题,还能自动处理图片压缩、内存缓存、无用请求取消等问题,稳定性和可维护性都更高。
额外提示
- 在
bindView复用item时,一定要记得清空ImageView的旧内容(比如设置占位图或null),避免滚动时看到旧图片残留。 - 你的AsyncTask没有取消机制,如果列表快速滚动,会有很多无用的请求在后台运行,浪费资源。成熟的图片库会自动取消不再需要的请求,这也是推荐使用它们的原因之一。
内容的提问来源于stack exchange,提问作者Europa
相关产品推荐
相关产品推荐

