Volley(2)源码分析
来源:互联网 发布:淘宝付款不发货骗术 编辑:程序博客网 时间:2024/04/30 15:58
由于Volley框架逻辑很清晰,类多但是都精简,很多都是接口。
第二篇,从入口开始,挨个分析Volley各个类的功能。
1.Volley.java
这个类是Volley框架的入口,其类图如下
成员变量只有一个String值,是默认的缓存文件名。
总共有4个方法,都叫newRequestQueue,用于构建RequestQueue。
其中,后3个方法最终都是通过调用第1个来实现的,没有传的参数都设为默认值。
来看第一个newRequestQueue方法。
String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } }
一般我们在调用Volley的时候并不会自己创建一个HttpStack传进去,这种情况下,Volley会根据当前的SDK_VERSION值来创建一个HttpStack。实际上现在的安卓手机已经几乎不存在低于SDK版本9的了。因此这里的stack基本上是个HurlStack。
Network network = new BasicNetwork(stack); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start();
第二步,用刚才的stack对象作为参数构建以个NetWork对象netWork,然后和一个DiskBasedCache对象一起作为参数构建1个RequestQueue,最后调用queue.start()。
总结下,整个流程如下:
可以通过参数maxDiskCacheBytes来指定Cache大小。默认值为5MB
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
2.DiskBasedCache.java
这个类并不是很重要,只要看一下google的注释就好拉。就是上面的Cache,默认大小为5MB
Cache implementation that caches files directly onto the hard disk in the specified directory. The default disk usage size is 5MB, but is configurable.
3.BasicNetwork.java
BasicNetwork实现了Network接口。因此大家都知道这个类的重点是什么了。
BasicNetwork中有2个重要的成员:HttpStack mHtppStack 和 ByteArrayPool mPool。
这两个成员都在其构造函数中传入。
public BasicNetwork(HttpStack httpStack)public BasicNetwork(HttpStack httpStack, ByteArrayPool pool)
前者调用了后者。
performRequest方法调用了下面的4个方法。
因此,从performRequest方法入手就能弄清楚这个类干了什么了。
long requestStart = SystemClock.elapsedRealtime(); while (true) { …… }
首先记录了时间,然后是个死循环,所有的东西都在死循环里面。死循环里是一个try{}catch{}串,try中:
// Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Handle moved resources if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { String newUrl = responseHeaders.get("Location"); request.setRedirectUrl(newUrl); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) { responseContents = entityToBytes(httpResponse.getEntity()); } else { // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } // if the request is slow, log it. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine); if (statusCode < 200 || statusCode > 299) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); }
这里,BasicNetwork把request交给成员mHttpStack去处理了。也就是说,所有的网络请求,都是HttpStack做的。
HttpStack负责了处理网络请求,并且返回HttpResponse。
Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers);
找return的地方,
第1处, HTTP304:
if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); }
return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
其中,
responseHeaders = convertHeaders(httpResponse.getAllHeaders()); responseContents = entityToBytes(httpResponse.getEntity());
convertHeaders负责把HttpResponse的header转化成Map形式。
entityToBytes负责把HttpResponse的Entity转化成Byte数组。
总结一下,BasicNetwork将request交给HttpStack处理,并从返回的HttpResponse中解析出Map形式的Header和Byte[]形式的数据。
但是为什么要一个死循环来做这件事呢。
看到各个catch{}块中,会发现有很多attemptRetryOnException(),只要不抛出错误(满足重试策略),就会一直attemptRetryOnException。
回头再研究重试策略的东西,先看RequestQueue。
用流程图来总结一下:
4.RequestQueue.java
RequestQueue是目前为止Volley中最庞大的类了,有320行,在这里去掉一些无关紧要的,精简一下。
它有2个内部接口,
/** Callback interface for completed requests. */ public static interface RequestFinishedListener<T> { /** Called when a request has finished processing. */ public void onRequestFinished(Request<T> request); } /** * A simple predicate or filter interface for Requests, for use by * {@link RequestQueue#cancelAll(RequestFilter)}. */ public interface RequestFilter { public boolean apply(Request<?> request); }
RequestFinishedListener是Request的结束监听,RequestFilter用于Request筛选,具体作用后面说。
它有3个构造函数,
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; } 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); }
3个参数的意义:
@param cache A Cache to use for persisting responses to disk //Response的缓存@param network A Network interface for performing HTTP requests //用于处理Http请求@param threadPoolSize Number of network dispatcher threads to create //network dispather数目
接下来是2个非常重要的成员:用于保存Cache请求和Network请求的2个队列
private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>(); private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();
此外RequestQueue中保存了正在处理的Request集合和等待中的Request集合。
private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>(); private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
最后3个需要提到的成员,1个CacheDispatcher、一个NetworkDispatcher数组(大小由构造函数中的threadPoolSize决定,默认为4),以及1个ResponseDelivery来分发请求结果。
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
/** Response delivery mechanism. */ private final ResponseDelivery mDelivery; /** The network dispatchers. */ private NetworkDispatcher[] mDispatchers; /** The cache dispatcher. */ private CacheDispatcher mCacheDispatcher;
public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
start方法中,启动了CacheDispatcher和全部的NetworkDispathcher。
public void cancelAll(RequestFilter filter) { synchronized (mCurrentRequests) { for (Request<?> request : mCurrentRequests) { if (filter.apply(request)) { request.cancel(); request.onFinish(); } } } }
这里的filter就是内部接口的实现了,用于cancel掉那些符合filter条件的request。
add方法的流程如下:
5.CacheDispatcher.java
CacheDispathcer的成员非常少,不算构造函数只有2个方法。
这5个成员的作用/含义如下:
mCacheQueue : 等待分类的resquest 队列
mNetworkQueue :被分到Network请求的request 队列
mDelivery : 用于分发response
mQuit: 线程终止的标识
其整个过程如下
6.NetworkDispatcher.java
NetworkDispatcher和CacheDispatcher相对应,用于分发走网络的request。
其run的流程如下
结果分发接口,内有3个方法
第一个postResponse直接调用的第二个postResponse,并传参数null。
8.ExecutorDelivery.java
实现了ResponseDelivery接口,用于分发response和error。
其有一个Runnable类型的内部类
private class ResponseDeliveryRunnable implements Runnable { private final Request mRequest; private final Response mResponse; private final Runnable mRunnable; public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) { mRequest = request; mResponse = response; mRunnable = runnable; } @SuppressWarnings("unchecked") @Override public void run() { // If this request has canceled, finish it and don't deliver. …… // Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } …… } }
其run方法如下:
public void postResponse(Request<?> request, Response<?> response) { postResponse(request, response, null); } @Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); } @Override public void postError(Request<?> request, VolleyError error) { request.addMarker("post-error"); Response<?> response = Response.error(error); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null)); }
ExecutorDelivery将分发任务交给内部类去处理,而内部类又把分发任务交给了request去处理。最终,分发任务到了各Request的实现类中处理。
此处以JsonRequest为例。
@Override protected void deliverResponse(T response) { if (mListener != null) { mListener.onResponse(response); } }
最终还是交给了mListener,也就是我们构造request的时候传入的onResponseListener和OnRequestListener。
总结一下,整个框架的Response流程如图
8.RetryPolicy.java
重试策略接口。只有3个方法
public int getCurrentTimeout(); public int getCurrentRetryCount(); public void retry(VolleyError error) throws VolleyError;
9.DefaultRetryPolicy.java
实现了RetryPolicy接口,是Volley默认的重试策略。
其重试策略为,当重试次数大于指定次数的时候,就抛出异常放弃重试。
@Override public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { throw error; } } /** * Returns true if this policy has attempts remaining, false otherwise. */ protected boolean hasAttemptRemaining() { return mCurrentRetryCount <= mMaxNumRetries; }
其中,指定次数mMaxNumRetries在构造函数中传入,大小由我们指定
public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { mCurrentTimeoutMs = initialTimeoutMs; mMaxNumRetries = maxNumRetries; mBackoffMultiplier = backoffMultiplier; }
10.Cache.java
缓存接口,提供了Get、remove、put、clear方法。有内部类Entry,封装了缓存数据。
总结几点使用过程中比较实用的:
1.NetworkDispatcher[ ]的size可以在RequestQueue的构造函数中传参指定,默认为4。
2.Cache的maxSize可以在newRequestQueue中以参数形式传入,默认为5MB。
3.重写Requst的getHeaders方法,放入我们自己需要的header。
4.可以自己实现RetryPolicy来定义自己的重试策略。
最后放一张Volley的总框架图,和圆圈相连的类我们可以自由地去实现,在Volley的核心代码中,这些部分都是以接口存在的,这就是Volley极强的扩展性所在。
本文在总结过程中参考了:
http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90
- Volley(2)源码分析
- Android Volley源码分析(2)
- 网络通讯框架-Volley源码分析(2)
- Android-Volley源码分析
- [Android]volley源码分析
- Volley源码分析
- Volley源码分析
- Volley源码分析
- Volley -- 源码分析
- Android-Volley源码分析
- Volley源码流程分析
- Volley源码分析
- Volley源码个人分析
- Volley框架源码分析
- Volley源码分析一
- Volley 源码分析
- Volley源码分析二
- volley源码分析
- ubuntu14.04安装cuda6.5简易版本,易操作
- 像素级实现设计稿笔记
- 《Motion Design for iOS》(四十三)
- 笔试题--“完数”(4)
- SDUTACM n a^o7 !
- Volley(2)源码分析
- photoshop启动提示:$$$/ADMDialog/ifontproblemWarning=解决办法
- 有12个苹果,1只香蕉,分给3个小孩,每个小孩都必须最少分到一个水果,求能分多少种?
- 利用MFC 对话框访问控件的七种方法
- 华为OJ——输入n个整数,输出其中最小的k个
- JavaScript基础
- 图结构练习——BFS——从起始点到目标点的最短步数
- sublime常用插件和常见问题
- MyBatis使用总结