Volley是Google推出的一款比较轻巧的网络请求框架,并且可以对请求进行缓存,同时可以实时取消请求,设置请求优先级,内置了ImageRequest,JsonRequest,JsonObjectRequest,JsonArrayRequest,StringRequest等,并且还支持自定义Request,基本上能满足日常的开发,当让Volley原生并不支持文件上传,但是可以通过自定义Request来实现,Volley不仅仅支持网络请求,还支持图片加载,这个主要是通过内置的ImageRequest来实现,Volley的工作原理大致如下:

大致流程就是,当添加一个Request的时候,首先会被添加到CachaQueue中,
正文
工作流程

Volley的缓存跟常规的缓存不太一致,它并不是直接去取缓存,而是构造了一个缓存队列,存放Request,然后根据特有的key值去取缓存,如果缓存存在并且没有过期,请求也没有取消,那么就直接解析缓存数据,发送到主线程,不然就直接加入到网络请求队列,重新请求网络数据,Volley的源码比较多,下面主要是从 Request , RequestQueue , Dispatcher , Cache ,这几个类分析一下Volley的一些实现细节,毕竟大部分框架,原理都是一两句话都能说清楚,但是有很多细节让自己实现其实还是挺困难的。
Request
继承关系

Request是一个单独的类,实现了Comparable接口,主要是用来对请求进行排序,如果设置了请求的优先级,就会根据优先级来进行排序,如果没有优先级就会按照请求加入的顺序来排序。
成员变量
private final int mMethod;//请求类型,GET,POST private final String mUrl;//请求的服务器地址 private final Object mLock = new Object();//用来给对象上锁 private Response.ErrorListener mErrorListener;//请求失败的监听 private Integer mSequence;//请求的序列号,按照请求的顺序依次递增 private RequestQueue mRequestQueue;//请求队列 private boolean mShouldCache = true;//是否需要缓存,默认开启缓存 private boolean mCanceled = false;//请求是否取消,默认为false private boolean mResponseDelivered = false;//解析完的请求是否已经发送 private boolean mShouldRetryServerErrors = false;//遇到服务器异常是否需要重试 private RetryPolicy mRetryPolicy;//重试策略 private Cache.Entry mCacheEntry = null;//缓存的 对象,里面封装了很多跟缓存相关的信息 private Object mTag;//请求的tag private NetworkRequestCompleteListener mRequestCompleteListener;//网络请求完成回调的结果 //Request的生命周期记录工具 private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;
Method
public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; int POST = 1; int PUT = 2; int DELETE = 3; int HEAD = 4; int OPTIONS = 5; int TRACE = 6; int PATCH = 7; }
由于方法的辨识度比较高,所以Volley没有采用枚举,而是采用了接口内定义变量,节省开销
Priority
public enum Priority { LOW, NORMAL, HIGH, IMMEDIATE }
优先级更注重可读性,所以Volley采用了枚举
构造方法
@Deprecated public Request(String url, Response.ErrorListener listener) { this(Method.DEPRECATED_GET_OR_POST, url, listener); } public Request(int method, String url, Response.ErrorListener listener) { mMethod = method; mUrl = url; mErrorListener = listener; setRetryPolicy(new DefaultRetryPolicy()); mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url); }
传入method,url以及失败的ErrorListener
关键方法
cancel
取消请求
public void cancel() { synchronized (mLock) { mCanceled = true;//改变请求标志位 mErrorListener = null;//回调接口置空 } }
compareTo
设置请求优先级
@Override public int compareTo(Request<T> other) { //获取请求优先级 Priority left = this.getPriority(); Priority right = other.getPriority(); //请求优先级默认为Normal //1.先比较请求优先级,如果相等再比较请求加入的顺序 return left == right ? this.mSequence - other.mSequence : right.ordinal() - left.ordinal(); }
finish
通知RequestQueue,这个请求已经结束
void finish(final String tag) { if (mRequestQueue != null) { //通知队列移除当前请求 mRequestQueue.finish(this); } if (MarkerLog.ENABLED) { final long threadId = Thread.currentThread().getId(); //判断当前线程是否为主线程,不是的话切换到主线程 if (Looper.myLooper() != Looper.getMainLooper()) { //通过PostRunnable的方式,保证请求结束的打印时间是有序的 Handler mainThread = new Handler(Looper.getMainLooper()); mainThread.post(new Runnable() { @Override public void run() { mEventLog.add(tag, threadId); mEventLog.finish(Request.this.toString()); } }); return; } mEventLog.add(tag, threadId); mEventLog.finish(this.toString()); } }
getCacheKey
默认作为请求的服务器地址作为key,实际开发过程中需要通过MD5会比较好一点
public String getCacheKey() { return getUrl(); }
抽象方法
Rquest是一个抽象类,里面还有很多抽象犯法需要子类去实现
//解析网络请求 abstract protected Response<T> parseNetworkResponse(NetworkResponse response); //传递网络请求结果 abstract protected void deliverResponse(T response); //请求失败的回调,因为不同的Request需要的返回类型不一样,需要子类实现,但是请求失败确是共同的 //所以Volley做了一些封装 public void deliverError(VolleyError error) { Response.ErrorListener listener; synchronized (mLock) { listener = mErrorListener; } if (listener != null) { listener.onErrorResponse(error); } }
RequesQueue
RequesQueue实际上是所有队列的一个管理类,包含正在进行中的队列集合mCurrentRequests,缓存队列mCacheQueue,网络队列mNetworkQueue等
成员变量
//Request添加进去后的序列号 private final AtomicInteger mSequenceGenerator = new AtomicInteger(); //正在进行中的请求集合,采用HashSet实现 private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>(); //请求的缓存队列,采用PriorityBlockingQueue实现,可以根据优先级来出队 private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<>(); //请求的网络队列,采用PriorityBlockingQueue实现 private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<>(); //网络请求分发器的数量,默认为4个 private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; //数据的缓存 private final Cache mCache; //网络请求的实际执行者 private final Network mNetwork; //网络请求返回结果的分发者 private final ResponseDelivery mDelivery; //网络请求分发器数组 private final NetworkDispatcher[] mDispatchers; //缓存分发器线程 private CacheDispatcher mCacheDispatcher; //网络请求完成的监听器集合 private final List<RequestFinishedListener> mFinishedListeners =new ArrayList<>();
构造方法
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); } //其它的构造方法最终还是间接调用了这个方法 public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }
通过成员变量的注释,比较清晰,就是默认初始化了一些变量
核心方法
start
public void start() { stop(); //终止正在进行的分发器,包括缓存的分发器以及网络分发器 // 创建缓存分发器 mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); //启动缓存分发器 mCacheDispatcher.start(); // 根据定义的Dispatcher数组,创建网络分发器 for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery); mDispatchers[i] = networkDispatcher; //启动网络分发器 networkDispatcher.start(); } } public void stop() { if (mCacheDispatcher != null) { mCacheDispatcher.quit(); } for (final NetworkDispatcher mDispatcher : mDispatchers) { if (mDispatcher != null) { mDispatcher.quit(); } } }
add
public <T> Request<T> add(Request<T> request) { //将RequestQueue赋值给Request request.setRequestQueue(this); //同步添加到正在进行中的请求集合中去 synchronized (mCurrentRequests) { mCurrentRequests.add(request); } //给请求设置序列号 request.setSequence(getSequenceNumber()); //添加Marker标记位 request.addMarker("add-to-queue"); if (!request.shouldCache()) { //如果请求队列不需要缓存,那么直接加入到网络对垒中 mNetworkQueue.add(request); return request; } //添加进缓存队列 mCacheQueue.add(request); return request; }
cancel
public void cancelAll(final Object tag) { if (tag == null) { throw new IllegalArgumentException("Cannot cancelAll with a null tag"); } cancelAll(new RequestFilter() { @Override public boolean apply(Request<?> request) { //通过tag来匹配需要取消的请求 return request.getTag() == tag; } }); } //通过RequestFilter来过滤需要取消的请求 public void cancelAll(RequestFilter filter) { synchronized (mCurrentRequests) { for (Request<?> request : mCurrentRequests) { if (filter.apply(request)) { request.cancel(); } } } }
finish
<T> void finish(Request<T> request) { // 从正在进行的请求中移除 synchronized (mCurrentRequests) { mCurrentRequests.remove(request); } synchronized (mFinishedListeners) { //移除回调接口 for (RequestFinishedListener<T> listener : mFinishedListeners) { listener.onRequestFinished(request); } } }
Dispatcher
Volley提供了两个分发器,一个是CacheDispatcher,一个是NetworkDispatcher,实际上就是两个线程,然后进行了死循环,不断地从缓存队列跟网络队列中进行取Request来进行分发。
CacheDispatcher
继承关系

成员变量
//Debug模式的标志 private static final boolean DEBUG = VolleyLog.DEBUG; //缓存队列,采用BlockingQueue实现生产者消费者模式 private final BlockingQueue<Request<?>> mCacheQueue; //网络队列,采用BlockingQueue实现生产者消费者模式 private final BlockingQueue<Request<?>> mNetworkQueue; //缓存类 private final Cache mCache; //网络请求结果分发类 private final ResponseDelivery mDelivery; //CacheDispatcher是否退出的标志 private volatile boolean mQuit = false; //等待管理队列管理器 private final WaitingRequestManager mWaitingRequestManager;
构造方法
public CacheDispatcher( BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue, Cache cache, ResponseDelivery delivery) { mCacheQueue = cacheQueue; mNetworkQueue = networkQueue; mCache = cache; mDelivery = delivery; mWaitingRequestManager = new WaitingRequestManager(this); }
CacheDispatcher持有cacheQueue,networkQueue,cache,delivery这几个类
run
@Override public void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); //设置线程优先级 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //缓存初始化,待会在缓存中具体分析 mCache.initialize(); while (true) { try { //死循环 processRequest(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } } } }
processRequest
private void processRequest() throws InterruptedException { //从缓存队列中取队列 final Request<?> request = mCacheQueue.take(); //给取出的Requet打上标记 request.addMarker("cache-queue-take"); //如果请求已取消,结束掉这个请求 if (request.isCanceled()) { request.finish("cache-discard-canceled"); return; } //拿到缓存的entry Cache.Entry entry = mCache.get(request.getCacheKey()); //缓存数据为空,就将Request添加进mNetworkQueue if (entry == null) { request.addMarker("cache-miss"); if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { mNetworkQueue.put(request); } return; } // 缓存过期,直接加入到网络队列 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { mNetworkQueue.put(request); } return; } //缓存有效,直接解析发送给主线程 request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); }
quit
退出线程
public void quit() { mQuit = true; //中断线程 interrupt(); }
NetworkDispatcher
继承关系

成员变量
//网络请求队列 private final BlockingQueue<Request<?>> mQueue; //网络请求的实际操作类 private final Network mNetwork; //缓存类 private final Cache mCache; //请求响应的结果发送者 private final ResponseDelivery mDelivery; //线程是否发送的标志 private volatile boolean mQuit = false;
构造方法
public NetworkDispatcher(BlockingQueue<Request<?>> queue, Network network, Cache cache, ResponseDelivery delivery) { mQueue = queue; mNetwork = network; mCache = cache; mDelivery = delivery; }
对比CacheDispatcher,发现少了缓存队列,不过也很好理解,因为既然都到了网络这边了,说明缓存肯定GG了,所以只需要在获取到网络请求结果之后,放入缓存中就行了。
run
run方法其实跟CacheDispatcher是一样的,只是processRequest有些区别
private void processRequest() throws InterruptedException { long startTimeMs = SystemClock.elapsedRealtime(); //从队列中取出一个队列 Request<?> request = mQueue.take(); try { request.addMarker("network-queue-take"); //请求取消,直接finished if (request.isCanceled()) { request.finish("network-discard-cancelled"); request.notifyListenerResponseNotUsable(); return; } addTrafficStatsTag(request); // 进行网络请求 NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // If the server returned 304 AND we delivered a response already, // we're done -- don't deliver a second identical response if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); request.notifyListenerResponseNotUsable(); return; } // 解析网络请求数据 Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); //如果请求结果需要缓存,那么缓存请求的结果 if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // 将解析好的数据发送给主线程 request.markDelivered(); mDelivery.postResponse(request, response); request.notifyListenerResponseReceived(response); } catch (VolleyError volleyError) { volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); parseAndDeliverNetworkError(request, volleyError); request.notifyListenerResponseNotUsable(); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); VolleyError volleyError = new VolleyError(e); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); mDelivery.postError(request, volleyError); request.notifyListenerResponseNotUsable(); } }
quit
public void quit() { mQuit = true; //中断线程 interrupt(); }
Cache
Volley的缓存主要是磁盘缓存,首先Volley提供了一个Cache接口,然后DiskBasedCache实现了这个接口,下面说一下这两个类
Cache
public interface Cache { Entry get(String key); void put(String key, Entry entry); void initialize(); void invalidate(String key, boolean fullExpire); void remove(String key); void clear(); class Entry { public byte[] data; public String etag; public long serverDate; public long lastModified; public long ttl; public long softTtl; public Map<String, String> responseHeaders = Collections.emptyMap(); public List<Header> allResponseHeaders; public boolean isExpired() { return this.ttl < System.currentTimeMillis(); } public boolean refreshNeeded() { return this.softTtl < System.currentTimeMillis(); } }
很常规的接口,只不过缓存的value不是请求的结果,而是封装了请求的数据的一个Entry,可以对缓存做一些判断。
DiskBaseCache
成员变量
//当前缓存的容量 private long mTotalSize = 0; //缓存的路径 private final File mRootDirectory; //分配的最大缓存容量 private final int mMaxCacheSizeInBytes; //默认的最大缓存容量 private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024; //缓存的负载因子,到达这个点之后会自动进行缓存清理 private static final float HYSTERESIS_FACTOR = 0.9f; //底层采用LinkedHashMap实现Lru算法,按照使用的顺序进行排序 private final Map<String, CacheHeader> mEntries = new LinkedHashMap<String, CacheHeader>(16, .75f, true);
构造方法
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) { mRootDirectory = rootDirectory; mMaxCacheSizeInBytes = maxCacheSizeInBytes; } public DiskBasedCache(File rootDirectory) { this(rootDirectory, DEFAULT_DISK_USAGE_BYTES); }
通过缓存的大小跟路径初始化DiskBasedCache
put
*/ @Override public synchronized void put(String key, Entry entry) { //检查容量是否合理,不合理就进行删除 pruneIfNeeded(entry.data.length); //获取缓存的文件 File file = getFileForKey(key); try { BufferedOutputStream fos = new BufferedOutputStream(createOutputStream(file)); CacheHeader e = new CacheHeader(key, entry); boolean success = e.writeHeader(fos); if (!success) { fos.close(); VolleyLog.d("Failed to write header for %s", file.getAbsolutePath()); throw new IOException(); } fos.write(entry.data); fos.close(); //缓存数据 putEntry(key, e); return; } catch (IOException e) { } boolean deleted = file.delete(); if (!deleted) { VolleyLog.d("Could not clean up file %s", file.getAbsolutePath()); } }
pruneIfNeed
private void pruneIfNeeded(int neededSpace) { //如果现有容量+即将存储的容量小于最大容量,返回 if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) { return; } long before = mTotalSize; int prunedFiles = 0; long startTime = SystemClock.elapsedRealtime(); Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator(); //遍历LinkedHashMap,删除链表头部的数据 while (iterator.hasNext()) { Map.Entry<String, CacheHeader> entry = iterator.next(); CacheHeader e = entry.getValue(); boolean deleted = getFileForKey(e.key).delete(); if (deleted) { mTotalSize -= e.size; } else { VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", e.key, getFilenameForKey(e.key)); } iterator.remove(); prunedFiles++; if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) { break; } } }
get
@Override public synchronized Entry get(String key) { //通过key获取缓存的entry CacheHeader entry = mEntries.get(key); //如果entry为null的话直接返回 if (entry == null) { return null; } //通过key获取到file文件 File file = getFileForKey(key); try { CountingInputStream cis = new CountingInputStream( new BufferedInputStream(createInputStream(file)), file.length()); try { CacheHeader entryOnDisk = CacheHeader.readHeader(cis); if (!TextUtils.equals(key, entryOnDisk.key)) { // File was shared by two keys and now holds data for a different entry! VolleyLog.d("%s: key=%s, found=%s", file.getAbsolutePath(), key, entryOnDisk.key); // Remove key whose contents on disk have been replaced. removeEntry(key); return null; } byte[] data = streamToBytes(cis, cis.bytesRemaining()); //将解析好的数据返回 return entry.toCacheEntry(data); } finally { // Any IOException thrown here is handled by the below catch block by design. //noinspection ThrowFromFinallyBlock cis.close(); } } catch (IOException e) { VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString()); remove(key); return null; } }
RetryPolicy
成员变量
private int mCurrentTimeoutMs;//超时时间 private int mCurrentRetryCount;//已重试次数 private final int mMaxNumRetries;//最大重试次数 private final float mBackoffMultiplier;//失败后重连的间隔因子 public static final int DEFAULT_TIMEOUT_MS = 2500;//默认超时时间 public static final int DEFAULT_MAX_RETRIES = 1;//默认重试次数 public static final float DEFAULT_BACKOFF_MULT = 1f;//默认的失败之后重连的间隔因子为1
构造方法
public DefaultRetryPolicy() { this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); } public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { mCurrentTimeoutMs = initialTimeoutMs; mMaxNumRetries = maxNumRetries; mBackoffMultiplier = backoffMultiplier; }
传入超时时间,最大重试次数,重试间隔
retry
@Override public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; //计算重试时间 mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { //如果到达最大次数,还是失败就抛异常 throw error; } }
Image
Volley不仅支持网络请求,还可以用来加载图片,主要相关的两个核心类是ImageLoader跟ImageRequest
ImageLoader
成员变量
private final RequestQueue mRequestQueue;//请求队列 private int mBatchResponseDelayMs = 100;//请求响应结果发送延时 private final ImageCache mCache;//图片缓存 //用HashMap来保存延时的请求 private final HashMap<String, BatchedImageRequest> mInFlightRequests = new HashMap<String, BatchedImageRequest>(); //HashMap来保存延时的请求响应结果 private final HashMap<String, BatchedImageRequest> mBatchedResponses = new HashMap<String, BatchedImageRequest>(); //切换线程的Handler private final Handler mHandler = new Handler(Looper.getMainLooper());
构造方法
public ImageLoader(RequestQueue queue, ImageCache imageCache) { mRequestQueue = queue; mCache = imageCache; }
get
public ImageContainer get(String requestUrl, final ImageListener listener) { return get(requestUrl, listener, 0, 0); }
间接调用
public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight) { return get(requestUrl, imageListener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE); }
继续调用
public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight, ScaleType scaleType) { // 检测是否在主线程 throwIfNotOnMainThread(); //通过转换得到缓存的key final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); // 从缓存中查找对应的bitmap Bitmap cachedBitmap = mCache.getBitmap(cacheKey); if (cachedBitmap != null) { //找到直接返回 ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); imageListener.onResponse(container, true); return container; } // 缓存失败,初始化ImageContainer ImageContainer imageContainer = new ImageContainer(null, requestUrl, cacheKey, imageListener); //回调 imageListener.onResponse(imageContainer, true); // 判断当前的请求是否在mBatchedResponses中 BatchedImageRequest request = mInFlightRequests.get(cacheKey); if (request != null) { // If it is, add this request to the list of listeners. request.addContainer(imageContainer); return imageContainer; } // 传达 Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,cacheKey); mRequestQueue.add(newRequest); mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; }
get方法返回的是一个ImageContainer,里面包好了很多跟Image相关的信息,类似Cache,mCacheKey,mRequestUrl,mListener。
ImageRequest
继承关系

ImageRequest继承自Request,然后定义的泛型是Bitmap
成员变量
//超时时间 public static final int DEFAULT_IMAGE_TIMEOUT_MS = 1000; //默认的重试次数 public static final int DEFAULT_IMAGE_MAX_RETRIES = 2; //默认重试延迟因子 public static final float DEFAULT_IMAGE_BACKOFF_MULT = 2f; private final Object mLock = new Object();//全局对象锁 private Response.Listener<Bitmap> mListener;//回调监听 private final Config mDecodeConfig;//解码的配置信息 private final int mMaxWidth;//ImageView传入的最大宽度 private final int mMaxHeight;//ImageView传入的最大高度 private final ScaleType mScaleType;//缩放类型 private static final Object sDecodeLock = new Object();//解码的同步锁
构造方法
@Deprecated public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, Config decodeConfig, Response.ErrorListener errorListener) { this(url, listener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE, decodeConfig, errorListener); } public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); setRetryPolicy(new DefaultRetryPolicy(DEFAULT_IMAGE_TIMEOUT_MS, DEFAULT_IMAGE_MAX_RETRIES, DEFAULT_IMAGE_BACKOFF_MULT)); mListener = listener; mDecodeConfig = decodeConfig; mMaxWidth = maxWidth; mMaxHeight = maxHeight; mScaleType = scaleType; }
构造方法里面都是一些配置信息,没什么好说的
cancel
@Override public void cancel() { super.cancel(); synchronized (mLock) { mListener = null; } }
跟前面的一个套路,不解释
doParse
网络请求回来之后,经过传递最终到了doParse方法
private Response<Bitmap> doParse(NetworkResponse response) { //拿到字节数组 byte[] data = response.data; BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); Bitmap bitmap = null; if (mMaxWidth == 0 && mMaxHeight == 0) { //传入的宽高都为0,不缩放,直接返回原始尺寸 decodeOptions.inPreferredConfig = mDecodeConfig; bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); } else { // If we have to resize this image, first get the natural bounds. //先不加载进内存 decodeOptions.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); //获取实际宽高 int actualWidth = decodeOptions.outWidth; int actualHeight = decodeOptions.outHeight; // 进行比例缩放,获取时间宽高 int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight, actualWidth, actualHeight, mScaleType); int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth, actualHeight, actualWidth, mScaleType); // 进行缩放 decodeOptions.inJustDecodeBounds = false; decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight); Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); // 如果有必要的话,把得到的bitmap的最大边进行压缩来适应尺寸 if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) { bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true); tempBitmap.recycle(); } else { bitmap = tempBitmap; } } if (bitmap == null) { //解析失败回调 return Response.error(new ParseError(response)); } else { //解析成功回调 return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response)); } }
Volley加载图片的大致流程就到了这里,可能会有些奇怪,Volley并没有采用Lrucache在内存中进行缓存,是因为ImageRequest继承自Request,所以就依赖于缓存队列,只有File的缓存,可能这也是为什么提到图片加载大家可能会想到很多的Fresco,Glide,Picasso,但是很少人会想到Volley,提到Volley想到的还是网络请求,没有LRUCache应该是最主要的原因了。
总结
Volley是一款扩展性很强的框架,抽取了Request基类,用户可以自定义任意的Request,底层并没有使用线程池,而是采用了四个网络线程从RequestQueue中取数据,如果是数据量较小的网络请求,使用起来比较灵活,如果网络请求比较耗时,那么Volley的四个线程可能就不够用了,我们可以创建更多的线程,但是线程的开销会很高,而且对线程的利用率不大,这个时候就需要使用线程池了。Volley提供图片加载的功能,但是没有实现内存缓存,所以性能不是很高。Volley原生没有提供图片上传功能,不过由于他的扩展性很好,所以我们可以自己继承Request类来实现这个功能。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。