[置顶] Android网络通信Volley框架源码浅析(三)

2024-06-10 07:18

本文主要是介绍[置顶] Android网络通信Volley框架源码浅析(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[置顶] Android网络通信Volley框架源码浅析(三)

标签: Volleyandroid开发框架源码

尊重原创 http://write.blog.csdn.net/postedit/26002961


通过前面浅析(一)和浅析(二)的分析,相信大家对于Volley有了初步的认识,但是如果想更深入的理解,还需要靠大家多多看源码。

这篇文章中我们主要来研究一下使用Volley框架请求大量图片的原理,在Android的应用中,通过http请求获取的数据主要有三类:

1、json 
2、xml
3、Image

其中json和xml的获取其实原理很简单,使用Volley获取感觉有点大财小用了,了解Volley获取图片的原理才是比较有意义的,因为里面涉及到很多知识点,比如获取大量图片如何防止OOM。


那么我们就开始研究源码吧。

(1) ImageLoader.java
通过它的名字我们就知道是用来加载Image的工具类


[java] view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2. 通过调用ImageLoader的get方法就可以获取到图片,然后通过一个Listener回调,将图片设置到ImgeView中(这个方法务必在主线程中调用) 
  3.  */  
  4. public class ImageLoader {  
  5.     /** 前面已经接触过,请求队列(其实不是真实的队列,里面包含了本地队列和网络队列) */  
  6.     private final RequestQueue mRequestQueue;  
  7.   
  8.      
  9.   
  10.     /** 图片缓冲,这个缓存不是前面提到的磁盘缓存,这个是内存缓存,我们可以通过LruCache实现这个接口 */  
  11.     private final ImageCache mCache;  
  12.   
  13.     /** 
  14.      * 用于存放具有相同cacheKey的请求 
  15.      */  
  16.     private final HashMap<String, BatchedImageRequest> mInFlightRequests =  
  17.             new HashMap<String, BatchedImageRequest>();  
  18.   
  19.     /** 用于存放具有相同Key,并且返回了数据的请求*/  
  20.     private final HashMap<String, BatchedImageRequest> mBatchedResponses =  
  21.             new HashMap<String, BatchedImageRequest>();  
  22.   
  23.     /** Handler to the main thread. */  
  24.     private final Handler mHandler = new Handler(Looper.getMainLooper());  
  25.   
  26.     /** Runnable for in-flight response delivery. */  
  27.     private Runnable mRunnable;  
  28.   
  29.     /** 
  30.      * Simple cache adapter interface. If provided to the ImageLoader, it 
  31.      * will be used as an L1 cache before dispatch to Volley. Implementations 
  32.      * must not block. Implementation with an LruCache is recommended. 
  33.      */  
  34.     public interface ImageCache {  
  35.         public Bitmap getBitmap(String url);  
  36.         public void putBitmap(String url, Bitmap bitmap);  
  37.     }  
  38.   
  39.     /** 
  40.      * 构造函数需要传入一个RequestQueue对象和一个内存缓存对象 
  41.      * @param queue The RequestQueue to use for making image requests. 
  42.      * @param imageCache The cache to use as an L1 cache. 
  43.      */  
  44.     public ImageLoader(RequestQueue queue, ImageCache imageCache) {  
  45.         mRequestQueue = queue;  
  46.         mCache = imageCache;  
  47.     }  
  48.   
  49.     /** 
  50.      * 用于图片获取成功或者失败的回调 
  51.      * @param imageView 需要设置图片的ImageView. 
  52.      * @param defaultImageResId 默认显示图片. 
  53.      * @param errorImageResId 出错时显示的图片. 
  54.      */  
  55.     public static ImageListener getImageListener(final ImageView view,  
  56.             final int defaultImageResId, final int errorImageResId) {  
  57.         return new ImageListener() {  
  58.             @Override  
  59.             public void onErrorResponse(VolleyError error) {  
  60.                 //出错并且设置了出错图片,那么显示出错图片  
  61.                 if (errorImageResId != 0) {  
  62.                     view.setImageResource(errorImageResId);  
  63.                 }  
  64.             }  
  65.   
  66.             @Override  
  67.             public void onResponse(ImageContainer response, boolean isImmediate) {  
  68.                 if (response.getBitmap() != null) {  
  69.                     //成功获取到了数据,则显示  
  70.                     view.setImageBitmap(response.getBitmap());  
  71.                 } else if (defaultImageResId != 0) {  
  72.                     //数据为空,那么显示默认图片  
  73.                     view.setImageResource(defaultImageResId);  
  74.                 }  
  75.             }  
  76.         };  
  77.     }  
  78.   
  79.      
  80.     /** 
  81.      * 判断图片是否已经缓存,不同尺寸的图片的cacheKey是不一样的 
  82.      * @param requestUrl 图片的url 
  83.      * @param maxWidth 请求图片的宽度. 
  84.      * @param maxHeight 请求图片的高度. 
  85.      * @return 返回true则缓存. 
  86.      */  
  87.     public boolean isCached(String requestUrl, int maxWidth, int maxHeight) {  
  88.         throwIfNotOnMainThread();  
  89.   
  90.         String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);  
  91.         return mCache.getBitmap(cacheKey) != null;  
  92.     }  
  93.   
  94.     /** 
  95.      * 这个方法时个核心方法,我们主要通过它来获取图片 
  96.      * 
  97.      * @param requestUrl The URL of the image to be loaded. 
  98.      * @param defaultImage Optional default image to return until the actual image is loaded. 
  99.      */  
  100.     public ImageContainer get(String requestUrl, final ImageListener listener) {  
  101.         return get(requestUrl, listener, 00);  
  102.     }  
  103.   
  104.     /** 
  105.      * 这个方法比上面方法多了两个参数,如果传入则图片大小会做相应处理,如果不传默认为0,图片大小不做处理 
  106.      * @param requestUrl The url of the remote image 
  107.      * @param imageListener The listener to call when the remote image is loaded 
  108.      * @param maxWidth The maximum width of the returned image. 
  109.      * @param maxHeight The maximum height of the returned image. 
  110.      * @return A container object that contains all of the properties of the request, as well as 
  111.      *     the currently available image (default if remote is not loaded). 
  112.      */  
  113.     public ImageContainer get(String requestUrl, ImageListener imageListener,  
  114.             int maxWidth, int maxHeight) {  
  115.         // only fulfill requests that were initiated from the main thread.  
  116.         throwIfNotOnMainThread();  
  117.         //获取key,其实就是url,width,height按照某种格式拼接  
  118.         final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);  
  119.   
  120.         // 首先从缓存里面取图片  
  121.         Bitmap cachedBitmap = mCache.getBitmap(cacheKey);  
  122.         if (cachedBitmap != null) {  
  123.             // 如果缓存命中,则直接放回  
  124.             ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, nullnull);  
  125.             imageListener.onResponse(container, true);  
  126.             return container;  
  127.         }  
  128.   
  129.         // 没有命中,则创建一个ImageContainer,注意此时图片数据传入的null,  
  130.         ImageContainer imageContainer =  
  131.                 new ImageContainer(null, requestUrl, cacheKey, imageListener);  
  132.   
  133.         // 这就是为什么在onResponse中我们需要判断图片数据是否为空,此时就是为空的  
  134.         imageListener.onResponse(imageContainer, true);  
  135.   
  136.         // 判断同一个key的请求是否已经存在  
  137.         BatchedImageRequest request = mInFlightRequests.get(cacheKey);  
  138.         if (request != null) {  
  139.             // 如果存在,则直接加入request中,没有必要对一个key发送多个请求  
  140.             request.addContainer(imageContainer);  
  141.             return imageContainer;  
  142.         }  
  143.   
  144.         // 发送一个请求,并加入RequestQueue  
  145.         Request<?> newRequest =  
  146.             new ImageRequest(requestUrl, new Listener<Bitmap>() {  
  147.                 @Override  
  148.                 public void onResponse(Bitmap response) {  
  149.                     //成功获取到图片  
  150.                     onGetImageSuccess(cacheKey, response);  
  151.                 }  
  152.             }, maxWidth, maxHeight,  
  153.             Config.RGB_565, new ErrorListener() {  
  154.                 @Override  
  155.                 public void onErrorResponse(VolleyError error) {  
  156.                     onGetImageError(cacheKey, error);  
  157.                 }  
  158.             });  
  159.         mRequestQueue.add(newRequest);  
  160.         VolleyLog.e("-------------->"+newRequest.getSequence());  
  161.         //加入到HashMap中,表明这个key已经存在一个请求  
  162.         mInFlightRequests.put(cacheKey,  
  163.                 new BatchedImageRequest(newRequest, imageContainer));  
  164.         return imageContainer;  
  165.     }  
  166.   
  167.      
  168.   
  169.     /** 
  170.      * Handler for when an image was successfully loaded. 
  171.      * @param cacheKey The cache key that is associated with the image request. 
  172.      * @param response The bitmap that was returned from the network. 
  173.      */  
  174.     private void onGetImageSuccess(String cacheKey, Bitmap response) {  
  175.         // 获取图片成功,放入缓存  
  176.         mCache.putBitmap(cacheKey, response);  
  177.   
  178.         // 将cacheKey对应的请求从mInFlightRequests中移除  
  179.         BatchedImageRequest request = mInFlightRequests.remove(cacheKey);  
  180.   
  181.         if (request != null) {  
  182.             // Update the response bitmap.  
  183.             request.mResponseBitmap = response;  
  184.   
  185.             // Send the batched response  
  186.             batchResponse(cacheKey, request);  
  187.         }  
  188.     }  
  189.   
  190.     /** 
  191.      * Handler for when an image failed to load. 
  192.      * @param cacheKey The cache key that is associated with the image request. 
  193.      */  
  194.     private void onGetImageError(String cacheKey, VolleyError error) {  
  195.         // Notify the requesters that something failed via a null result.  
  196.         // Remove this request from the list of in-flight requests.  
  197.         BatchedImageRequest request = mInFlightRequests.remove(cacheKey);  
  198.   
  199.         if (request != null) {  
  200.             // Set the error for this request  
  201.             request.setError(error);  
  202.   
  203.             // Send the batched response  
  204.             batchResponse(cacheKey, request);  
  205.         }  
  206.     }  
  207.   
  208.     /** 
  209.      * Container object for all of the data surrounding an image request. 
  210.      */  
  211.     public class ImageContainer {  
  212.         /** 
  213.          * 保存从网络获取的图片 
  214.          */  
  215.         private Bitmap mBitmap;  
  216.   
  217.         private final ImageListener mListener;  
  218.   
  219.         /** The cache key that was associated with the request */  
  220.         private final String mCacheKey;  
  221.   
  222.         /** The request URL that was specified */  
  223.         private final String mRequestUrl;  
  224.   
  225.         /** 
  226.          * Constructs a BitmapContainer object. 
  227.          * @param bitmap The final bitmap (if it exists). 
  228.          * @param requestUrl The requested URL for this container. 
  229.          * @param cacheKey The cache key that identifies the requested URL for this container. 
  230.          */  
  231.         public ImageContainer(Bitmap bitmap, String requestUrl,  
  232.                 String cacheKey, ImageListener listener) {  
  233.             mBitmap = bitmap;  
  234.             mRequestUrl = requestUrl;  
  235.             mCacheKey = cacheKey;  
  236.             mListener = listener;  
  237.         }  
  238.   
  239.         /** 
  240.          * 取消一个图片请求 
  241.          */  
  242.         public void cancelRequest() {  
  243.             if (mListener == null) {  
  244.                 return;  
  245.             }  
  246.             //判断此key对应的请求有没有  
  247.             BatchedImageRequest request = mInFlightRequests.get(mCacheKey);  
  248.             if (request != null) {  
  249.                 /**如果存在,request中mContainers中的这个Container,如果mContainers的size为0,那么 
  250.                     removeContainerAndCancelIfNecessary返回true 
  251.                 */  
  252.                 boolean canceled = request.removeContainerAndCancelIfNecessary(this);  
  253.                 if (canceled) {  
  254.                     //如果返回true,那么说明没有任何一个ImageView对这个请求感兴趣,需要移除它  
  255.                     mInFlightRequests.remove(mCacheKey);  
  256.                 }  
  257.             } else {  
  258.                 // 判断是否这个request已经成功返回了  
  259.                 request = mBatchedResponses.get(mCacheKey);  
  260.                 if (request != null) {  
  261.                     request.removeContainerAndCancelIfNecessary(this);  
  262.                     if (request.mContainers.size() == 0) {  
  263.                         //如果已经成功返回,并且没有ImageView对他感兴趣,那么删除它  
  264.                         mBatchedResponses.remove(mCacheKey);  
  265.                     }  
  266.                 }  
  267.             }  
  268.         }  
  269.   
  270.         /** 
  271.          * Returns the bitmap associated with the request URL if it has been loaded, null otherwise. 
  272.          */  
  273.         public Bitmap getBitmap() {  
  274.             return mBitmap;  
  275.         }  
  276.   
  277.         /** 
  278.          * Returns the requested URL for this container. 
  279.          */  
  280.         public String getRequestUrl() {  
  281.             return mRequestUrl;  
  282.         }  
  283.     }  
  284.   
  285.     /** 
  286.      * 对Request的一个包装,将所有有共同key的请求放入一个LinkedList中 
  287.      */  
  288.     private class BatchedImageRequest {  
  289.         /** The request being tracked */  
  290.         private final Request<?> mRequest;  
  291.   
  292.         /** The result of the request being tracked by this item */  
  293.         private Bitmap mResponseBitmap;  
  294.   
  295.         /** Error if one occurred for this response */  
  296.         private VolleyError mError;  
  297.   
  298.         /** 存放具有共同key的ImageContainer*/  
  299.         private final LinkedList<ImageContainer> mContainers = new LinkedList<ImageContainer>();  
  300.   
  301.         /** 
  302.          * Constructs a new BatchedImageRequest object 
  303.          * @param request The request being tracked 
  304.          * @param container The ImageContainer of the person who initiated the request. 
  305.          */  
  306.         public BatchedImageRequest(Request<?> request, ImageContainer container) {  
  307.             mRequest = request;  
  308.             mContainers.add(container);  
  309.         }  
  310.   
  311.         /** 
  312.          * Set the error for this response 
  313.          */  
  314.         public void setError(VolleyError error) {  
  315.             mError = error;  
  316.         }  
  317.   
  318.         /** 
  319.          * Get the error for this response 
  320.          */  
  321.         public VolleyError getError() {  
  322.             return mError;  
  323.         }  
  324.   
  325.         /** 
  326.          * Adds another ImageContainer to the list of those interested in the results of 
  327.          * the request. 
  328.          */  
  329.         public void addContainer(ImageContainer container) {  
  330.             mContainers.add(container);  
  331.         }  
  332.   
  333.         /** 
  334.          * 移除一个ImageContainer,如果此时size==0,那么需要从mInFlightRequests中移除该BatchedImageRequest 
  335.          * @param container The container to remove from the list 
  336.          * @return True if the request was canceled, false otherwise. 
  337.          */  
  338.         public boolean removeContainerAndCancelIfNecessary(ImageContainer container) {  
  339.             mContainers.remove(container);  
  340.             if (mContainers.size() == 0) {  
  341.                 mRequest.cancel();  
  342.                 return true;  
  343.             }  
  344.             return false;  
  345.         }  
  346.     }  
  347.   
  348.     /** 
  349.      * 当请求返回后,将BatchedImageRequest放入到mBatchedResponses,然后将结果发送给所有具有相同key的ImageContainer,ImageContainer通过里面的Listener发送到ImageView,从而显示出来 
  350.      * @param cacheKey The cacheKey of the response being delivered. 
  351.      * @param request The BatchedImageRequest to be delivered. 
  352.      * @param error The volley error associated with the request (if applicable). 
  353.      */  
  354.     private void batchResponse(String cacheKey, BatchedImageRequest request) {  
  355.         mBatchedResponses.put(cacheKey, request);  
  356.         // If we don't already have a batch delivery runnable in flight, make a new one.  
  357.         // Note that this will be used to deliver responses to all callers in mBatchedResponses.  
  358.         if (mRunnable == null) {  
  359.             mRunnable = new Runnable() {  
  360.                 @Override  
  361.                 public void run() {  
  362.                     for (BatchedImageRequest bir : mBatchedResponses.values()) {  
  363.                         for (ImageContainer container : bir.mContainers) {  
  364.                             // If one of the callers in the batched request canceled the request  
  365.                             // after the response was received but before it was delivered,  
  366.                             // skip them.  
  367.                             if (container.mListener == null) {  
  368.                                 continue;  
  369.                             }  
  370.                             if (bir.getError() == null) {  
  371.                                 container.mBitmap = bir.mResponseBitmap;  
  372.                                 container.mListener.onResponse(container, false);  
  373.                             } else {  
  374.                                 container.mListener.onErrorResponse(bir.getError());  
  375.                             }  
  376.                         }  
  377.                     }  
  378.                     mBatchedResponses.clear();  
  379.                     mRunnable = null;  
  380.                 }  
  381.   
  382.             };  
  383.             // Post the runnable.  
  384.             mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);  
  385.         }  
  386.     }  
  387.   
  388.     
  389.     /** 
  390.      * 获取一个请求的key,拼接规则就是使用#讲几个连接起来 
  391.      * @param url The URL of the request. 
  392.      * @param maxWidth The max-width of the output. 
  393.      * @param maxHeight The max-height of the output. 
  394.      */  
  395.     private static String getCacheKey(String url, int maxWidth, int maxHeight) {  
  396.         return new StringBuilder(url.length() + 12).append("#W").append(maxWidth)  
  397.                 .append("#H").append(maxHeight).append(url).toString();  
  398.     }  
  399.       
  400.       
  401. }  


ImageLoader的代码还是比较复杂的,但是思路还是比较清晰的,总结如下:
1、通过ImageLoader的get方法获取图片,如果我们只想获取原始图片,不用关心大小,则只用传入url和Listener,如果需要设置图片大小,那么传入你需要设置大大小
2、get方法中,先回去缓存中查找,如果命中,那么就直接放回,如果没有命中,那么就判断mInFlightRequests中是否有相同key的BatchedImageRequest,如果有则直接将ImageConainer加入BatchedImageRequest的mContainres中,因为对于同一个key没有必要发送两次请求
3、如果在mInFlightRequest中没有此key,那么需要创建一个ImageRequest对象,并加入RequestQueue中,并使用ImageRequest创建一个BatchedImageRequest加入mInFlightRequest
4、当请求返回后,将BatchedImageRequest从mInFlightRequest中移除,加入mBatchedResponses中,将返回结果返回给所有的ImageContainer
5、如果一个ImageContainer在收到返回结果之前就被cancel掉,那么需要将它从mInFlightRequest的mContainers中移除,如果移除后mContainers的size为0,说明这个请求只有一次,取消了就没有必要请求,需要把BatchedImageRequestmInFlightRequest中移走,从如果不等于0,说明这个请求被其他的ImageContainr需要,不能取消


如果我们仅仅是获取少量图片,Volley框架为我们提供了一个NetworkImageView,这个类继承自ImageView,使用时,我们只需要调用setImageUrl即可,下面就来看其实现机制
(2) NetworkImageView.java


[java] view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class NetworkImageView extends ImageView {  
  2.     /** 需要加载图片的url */  
  3.     private String mUrl;  
  4.   
  5.     /** 
  6.      * 默认显示图片的id 
  7.      */  
  8.     private int mDefaultImageId;  
  9.   
  10.     /** 
  11.      * 错误图片的id 
  12.      */  
  13.     private int mErrorImageId;  
  14.   
  15.     /** ImageLoader对象,其实就是用该对象去获取图片,所以了解了ImageLoader后,这个类很好理解 */  
  16.     private ImageLoader mImageLoader;  
  17.   
  18.     /**把这个对象当成url和Listener的封装即可 */  
  19.     private ImageContainer mImageContainer;  
  20.   
  21.     public NetworkImageView(Context context) {  
  22.         this(context, null);  
  23.     }  
  24.   
  25.     public NetworkImageView(Context context, AttributeSet attrs) {  
  26.         this(context, attrs, 0);  
  27.     }  
  28.   
  29.     public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {  
  30.         super(context, attrs, defStyle);  
  31.     }  
  32.   
  33.     /** 
  34.      * 设置Url 
  35.      * 
  36.      * @param url The URL that should be loaded into this ImageView. 
  37.      * @param imageLoader ImageLoader that will be used to make the request. 
  38.      */  
  39.     public void setImageUrl(String url, ImageLoader imageLoader) {  
  40.         mUrl = url;  
  41.         mImageLoader = imageLoader;  
  42.         // 这个方法我们后面分析  
  43.         loadImageIfNecessary(false);  
  44.     }  
  45.   
  46.     /** 
  47.      * Sets the default image resource ID to be used for this view until the attempt to load it 
  48.      * completes. 
  49.      */  
  50.     public void setDefaultImageResId(int defaultImage) {  
  51.         mDefaultImageId = defaultImage;  
  52.     }  
  53.   
  54.     /** 
  55.      * Sets the error image resource ID to be used for this view in the event that the image 
  56.      * requested fails to load. 
  57.      */  
  58.     public void setErrorImageResId(int errorImage) {  
  59.         mErrorImageId = errorImage;  
  60.     }  
  61.   
  62.     /** 
  63.      * 这个方法在onLayout方法中传入true,其他地方传入false 
  64.      * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise. 
  65.      */  
  66.     void loadImageIfNecessary(final boolean isInLayoutPass) {  
  67.         int width = getWidth();  
  68.         int height = getHeight();  
  69.   
  70.         boolean wrapWidth = false, wrapHeight = false;  
  71.         if (getLayoutParams() != null) {  
  72.             wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;  
  73.             wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;  
  74.         }  
  75.   
  76.         // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content  
  77.         // view, hold off on loading the image.  
  78.         boolean isFullyWrapContent = wrapWidth && wrapHeight;  
  79.         if (width == 0 && height == 0 && !isFullyWrapContent) {  
  80.             return;  
  81.         }  
  82.   
  83.         // if the URL to be loaded in this view is empty, cancel any old requests and clear the  
  84.         // currently loaded image.  
  85.         if (TextUtils.isEmpty(mUrl)) {  
  86.             if (mImageContainer != null) {  
  87.                 mImageContainer.cancelRequest();  
  88.                 mImageContainer = null;  
  89.             }  
  90.             setDefaultImageOrNull();  
  91.             return;  
  92.         }  
  93.   
  94.         // if there was an old request in this view, check if it needs to be canceled.  
  95.         if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {  
  96.             if (mImageContainer.getRequestUrl().equals(mUrl)) {  
  97.                 //如果请求url相同,则直接return  
  98.                 return;  
  99.             } else {  
  100.                 // 请求url不同,则cancel,并显示默认图片或者不显示图片  
  101.                 mImageContainer.cancelRequest();  
  102.                 setDefaultImageOrNull();  
  103.             }  
  104.         }  
  105.   
  106.         // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.  
  107.         int maxWidth = wrapWidth ? 0 : width;  
  108.         int maxHeight = wrapHeight ? 0 : height;  
  109.   
  110.         //调用了get方法  
  111.         ImageContainer newContainer = mImageLoader.get(mUrl,  
  112.                 new ImageListener() {  
  113.                     @Override  
  114.                     public void onErrorResponse(VolleyError error) {  
  115.                         if (mErrorImageId != 0) {  
  116.                             setImageResource(mErrorImageId);  
  117.                         }  
  118.                     }  
  119.   
  120.                     @Override  
  121.                     public void onResponse(final ImageContainer response, boolean isImmediate) {  
  122.                         // If this was an immediate response that was delivered inside of a layout  
  123.                         // pass do not set the image immediately as it will trigger a requestLayout  
  124.                         // inside of a layout. Instead, defer setting the image by posting back to  
  125.                         // the main thread.  
  126.                         if (isImmediate && isInLayoutPass) {  
  127.                             post(new Runnable() {  
  128.                                 @Override  
  129.                                 public void run() {  
  130.                                     onResponse(response, false);  
  131.                                 }  
  132.                             });  
  133.                             return;  
  134.                         }  
  135.   
  136.                         if (response.getBitmap() != null) {  
  137.                             setImageBitmap(response.getBitmap());  
  138.                         } else if (mDefaultImageId != 0) {  
  139.                             setImageResource(mDefaultImageId);  
  140.                         }  
  141.                     }  
  142.                 }, maxWidth, maxHeight);  
  143.   
  144.         // update the ImageContainer to be the new bitmap container.  
  145.         mImageContainer = newContainer;  
  146.     }  
  147.   
  148.     private void setDefaultImageOrNull() {  
  149.         if(mDefaultImageId != 0) {  
  150.             setImageResource(mDefaultImageId);  
  151.         }  
  152.         else {  
  153.             setImageBitmap(null);  
  154.         }  
  155.     }  
  156.   
  157.     @Override  
  158.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  159.         super.onLayout(changed, left, top, right, bottom);  
  160.         loadImageIfNecessary(true);  
  161.     }  
  162.   
  163.     @Override  
  164.     protected void onDetachedFromWindow() {  
  165.         if (mImageContainer != null) {  
  166.             // If the view was bound to an image request, cancel it and clear  
  167.             // out the image from the view.  
  168.             mImageContainer.cancelRequest();  
  169.             setImageBitmap(null);  
  170.             // also clear out the container so we can reload the image if necessary.  
  171.             mImageContainer = null;  
  172.         }  
  173.         super.onDetachedFromWindow();  
  174.     }  
  175.   
  176.     @Override  
  177.     protected void drawableStateChanged() {  
  178.         super.drawableStateChanged();  
  179.         invalidate();  
  180.     }  
  181. }  

到目前为止Volley框架的源码分析差不多了,下一篇文章我打算使用一个GridView展示大量图片的例子来讲解Volley的使用.....

这篇关于[置顶] Android网络通信Volley框架源码浅析(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1047498

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存