当前位置:   article > 正文

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

appcompatimageview的load_image加载图片失败

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

         开始我的代码是这样的:

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

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

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

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


  1. /** @throws TaskCancelledException if target ImageAware is collected by GC */
  2. private void checkViewReused() throws TaskCancelledException {
  3. if (isViewReused()) {
  4. throw new TaskCancelledException();
  5. }
  6. }


而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加载一遍,一切问题解决:

  1. if (!Util.fillNullStr(data.photo).equals("")){
  2. holder.item_model_image.
  3. imageLoader.displayImage((String) holder.item_model_image.getTag() , holder.item_model_image,
  4. mNormalImageOptions);
  5. }
  6. else{
  7. imageLoader.displayImage(null, holder.item_model_image,mNormalImageOptions);
  8. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/105812
推荐阅读
相关标签
  

闽ICP备14008679号