您的位置:首页 > 其它

由universal imageloader图片加载器为重用ImageView加载图片显示错误引起的思考...

2014-09-04 15:05 585 查看
一段非常普通的getview中用imageloader加载图片的代码,却怎么都会让第一个item的图片显示错误(本来应该显示blank图片,但却显示了其他网络上取回来的图片),这个listview的要求是这样的,若photo这个字段有值,则从网络上取回图片显示,没有值则从resource里面加载blank图片。

开始我的代码是这样的:

holder.item_model_image.setImageResource(R.drawable.blankmodel);
if (!Util.fillNullStr(data.photo).equals("")){
holder.item_model_image.
imageLoader.displayImage((String) holder.item_model_image.getTag() , holder.item_model_image,
mNormalImageOptions);
}


咋一看,没问题吧?但问题确实来了! 早上各种debug、各种谷歌甚至去到它的老巢https://github.com/nostra13/Android-Universal-Image-Loader里面 看issues,结果没发现有人提过这个问题。下午回来仔细分析它的代码发现,其实它有检测是否ImageView控件是否已经更其他Uri关联的,而且检查做得非常全面到位。

在仔细翻查每行代码,发现LoadAndDisplayImageTask.java里面的这个函数,没错,就是通过它来检查ImageView是不是被重用的:

/** @return <b>true</b> - if current ImageAware is reused for displaying another image; <b>false</b> - otherwise */
private boolean isViewReused() {
String currentCacheKey = engine.getLoadingUriForView(imageAware);
// Check whether memory cache key (image URI) for current ImageAware is actual.
// If ImageAware is reused for another task then current task should be cancelled.
boolean imageAwareWasReused = !memoryCacheKey.equals(currentCacheKey);
if (imageAwareWasReused) {
L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);
return true;
}
return false;
}


/** @throws TaskCancelledException if target ImageAware is collected by GC */
private void checkViewReused() throws TaskCancelledException {
if (isViewReused()) {
throw new TaskCancelledException();
}
}


而engine的getLoadingUriForView实现为:

String getLoadingUriForView(ImageAware imageAware) {

return cacheKeysForImageAwares.get(imageAware.getId());

}

cacheKeysForImageAwares这个实例则定义为:Map<Integer, String> cacheKeysForImageAwares = Collections

.synchronizedMap(new HashMap<Integer, String>());

看到了吧?它是通过要加载的视图,然后在cacheKeysForImageAwares 里面找回它的Uri,然后跟当前的Uri对比,若不相等则认为是重用,而checkViewReused()则检测重用则抛出异常让任务终止,有效防止图片错位。

但是,若这个ImageView虽然存在在listview的某个item里面(如我上面自己写的代码),之前没被imageloader加载过,当此View再次被使用并需要显示新图片时,然而cacheKeysForImageAwares表里没有记录,isViewReused()返回false,也就避开checkViewReused()的异常,顺利显示已经下载完的图片,把旧图片冲掉。

查到这个原因后就容易修改了,不管是否需要显示图片,imageview都用imageloader加载一遍,一切问题解决:

if (!Util.fillNullStr(data.photo).equals("")){
holder.item_model_image.
imageLoader.displayImage((String) holder.item_model_image.getTag() , holder.item_model_image,
mNormalImageOptions);
}
else{
imageLoader.displayImage(null, holder.item_model_image,mNormalImageOptions);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐