Listview中图片加载使用Volley框架时,出现图片显示不正确的问题的解析

  当我们开发企业级应用的时候,一般都会选择使用已经封装好的http框架。开源的比较流行的有:volley, android-async-http, retrofit, okhttp, androidquery , androidAsync 等。他们各有优劣,不同的框架有不同的效率,在使用的时候可以因地制宜地测试,根据效果来选择使用哪个,之前个人则比较喜欢用android-async- http,。如今Google推出了官方的针对Android平台上的网络通信库volley,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们没有理由不跟上时代的潮流。另外,但volley的扩展性很强,可以根据需要定制你自己的网络请求。所以,最后推荐还是使用volley进行开发,当然其他几个库也是非常具有学习以及参考意义的,可以将他们的精髓之处汲取到volley框架的拓展开发之中,做出自己理想的http通讯框架。


  但是今天突然遇到一些奇怪的问题,当listview每一个item中的图片都使用volley下载时,会出现图片显示乱序的问题,纠结了好久,经过不断的调试,终于找到了问题,与大家分享一下!大笑大笑大笑大笑


  使用volley框架,下载图片最主要的部分肯定是ImageLoader,而问题也就出在这里。请看下面这段代码:

  1. public ImageContainer get(ImageView imgView, String requestUrl, ImageListener imageListener,  
  2.         int maxWidth, int maxHeight) {  
  3.     // only fulfill requests that were initiated from the main thread.  
  4.     throwIfNotOnMainThread();  
  5.   
  6.     final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);  
  7.   
  8.     // Try to look up the request in the cache of remote images.  
  9.     Bitmap cachedBitmap = mCache.getBitmap(cacheKey);  
  10.     if (cachedBitmap != null) {  
  11.         // Return the cached bitmap.  
  12.         ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, nullnull, imgView);  
  13.         imageListener.onResponse(container, true);  
  14.         return container;  
  15.     }  
  16.   
  17.     // The bitmap did not exist in the cache, fetch it!  
  18.     ImageContainer imageContainer =  
  19.             new ImageContainer(null, requestUrl, cacheKey, imageListener, imgView);  
  20.   
  21.     // Update the caller to let them know that they should use the default bitmap.  
  22.     imageListener.onResponse(imageContainer, true);  
  23.   
  24.     // Check to see if a request is already in-flight.  
  25.     BatchedImageRequest request = mInFlightRequests.get(cacheKey);  
  26.     if (request != null) {  
  27.         // If it is, add this request to the list of listeners.  
  28.         request.addContainer(imageContainer);  
  29.         return imageContainer;  
  30.     }  
  31.   
  32.     // The request is not already in flight. Send the new request to the network and  
  33.     // track it.  
  34.     Request<?> newRequest =  
  35.         new ImageRequest(requestUrl, new Listener<Bitmap>() {  
  36.             @Override  
  37.             public void onResponse(Bitmap response) {  
  38.                 onGetImageSuccess(cacheKey, response);  
  39.             }  
  40.         }, maxWidth, maxHeight,  
  41.         Config.RGB_565, new ErrorListener() {  
  42.             @Override  
  43.             public void onErrorResponse(VolleyError error) {  
  44.                 onGetImageError(cacheKey, error);  
  45.             }  
  46.         });  
  47.   
  48.     mRequestQueue.add(newRequest);  
  49.     mInFlightRequests.put(cacheKey,  
  50.             new BatchedImageRequest(newRequest, imageContainer));  
  51.     return imageContainer;  
  52. }  

  首先,这段代码的意思是check缓存中是否有你想要的图片的url地址,如果有,直接在缓存中取,缓存中如果没有,将创建新的请求(newRequest),并加入到mInFlightRequests这个请求hasmap中,  大家仔细看,你会在上面代码中找到这样一段:

  1. <span style="white-space:pre">    </span>// Check to see if a request is already in-flight.  
  2.         BatchedImageRequest request = mInFlightRequests.get(cacheKey);  
  3.         if (request != null) {  
  4.             // If it is, add this request to the list of listeners.  
  5.             request.addContainer(imageContainer);  
  6.             return imageContainer;  
  7.         }  

  它的意思是检测mInFlightRequests这个请求hasmap中是否已经包含你想要下载的图片,如果有,将这个请求加入到批量处理的请求(BatchedImageRequest)中, 为什么要这样做?其实volley是想帮你解决这样一种情况:假如有2个地方都需要下载同样的图片,而这张图片并没有下载完成(也就是说没办法去缓存中取图片数据),那么volley就会把这两个请求都保存起来,当下载完成后,统一返回给这2个请求的view,这样就不需要下载2遍重复的请求。

  那么问题来了,listview图片乱序和这里有什么关系呢?  listview控件一直存在这样一个问题:当你没有对listview的高度做设置时,listview就会将每个item都调用2遍getView(有时甚至更多次)。如果你的下载过程写在getview中,每个item就会被执行2次下载过程, 也就是说,上面的这段代码将被执行2次,所以,如果你debug,你会发现你上一次保存的view居然神奇的都变成了listview中第一个item的view,那么每次下载完图片,你就会看到图片乱序了。

   修改方法,请看下面代码:

  1. // Check to see if a request is already in-flight.  
  2.         BatchedImageRequest request = mInFlightRequests.get(cacheKey);  
  3.         if (request != null) {  
  4.             // If it is, add this request to the list of listeners.  
  5.             //request.addContainer(imageContainer);  
  6.             //由于list显示图片出现乱序问题,因为list会设置2遍,而第一遍加载的所有view都是第一个view(可以通过id看出),所以会出现第一个view不停的换图片的问题,解决方法,将add改为修改原始值  
  7.             request.clean();  
  8.             request.addContainer(imageContainer);  
  9.             return imageContainer;  
  10.         }  
   我只是暂时的修改了这个问题,但我认为这并不是一个最终的解决方案,如果大家有好方法请联系我。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值