經典錯誤現場
holder.image.setTag(ranklist.get(position).getRank());
holder.image.setImageResource(R.drawable.ph_user);
// ... 異步載入 ...
if (holder.image.getTag().equals(position+1) ...) // 錯誤判斷
根本原因
- Tag 設定時機錯:
setTag 應存**目標 URL/唯一標識**,而非 position(position 隨滾動變化)。
- 異步回調未驗證 Tag:圖片載入完成時,該 View 可能已被回收給其他 position,直接
setImageBitmap 會導致圖片錯位/閃爍。
- 同步/異步混用:代碼中同時有
setImageResource(同步)與 imageloader.displayImage(異步),邏輯衝突。
標準修正模式
String url = ranklist.get(position).getAvatar();
holder.image.setTag(url); // 1. Tag 存 URL
holder.image.setImageResource(R.drawable.placeholder); // 2. 先顯示佔位圖
if (!TextUtils.isEmpty(url)) {
imageLoader.displayImage(url, holder.image, options,
new ImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// 3. 關鍵:再次驗證 Tag 是否仍匹配
if (url.equals(view.getTag())) {
((ImageView)view).setImageBitmap(loadedImage);
}
}
// ... 其他回調
});
} else {
holder.image.setImageResource(R.drawable.default_avatar);
}
現代最佳實踐
- 棄用 ListView,**改用 RecyclerView + Glide/Picasso/Coil**,內建完整的請求取消、Tag 驗證、生命週期綁定。
- 若必須維護 ListView,封裝通用
bindView(ViewHolder, int position) 邏輯,統一處理異步載入與 Tag 驗證。