你好,我是 N0tExpectErr0r,一名热爱技术的 Android 开发html
个人我的博客:blog.N0tExpectErr0r.cnandroid
本篇源码解析基于 Volley 1.1.1git
Volley 是 Google 开发的一款网络请求框架,目前已中止更新。虽然目前你们的关注焦点都在 Retrofit、OkHttp 等第三方网络请求框架,团队的项目中所用的也是这两个框架,但 Volley 中仍是有很是多优秀的设计思想值得咱们去学习的。所以今天准备来学习一下 Volley 的源码,了解一下它的核心设计思想。github
咱们先看到 Volley 的入口——Volley
类。缓存
Volley 在使用以前,咱们须要一个请求队列对象 RequestQueue
,通常整个应用统一用同一个 RequestQueue
,让咱们看看建立它的方法 Volley.newRequestQueue(Context)
:安全
/**
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
*
* @param context A {@link Context} to use for creating the cache dir.
* @return A started {@link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (BaseHttpStack) null);
}
复制代码
它转调到了 Volley.newRequestQueue(Context, BaseHttpStack)
方法,同时还有一个 Volley.newRequestQueue(Context, HttpStack)
方法:bash
/**
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
*
* @param context A {@link Context} to use for creating the cache dir.
* @param stack An {@link HttpStack} to use for the network, or null for default.
* @return A started {@link RequestQueue} instance.
* @deprecated Use {@link #newRequestQueue(Context, BaseHttpStack)} instead to avoid depending
* on Apache HTTP. This method may be removed in a future release of Volley.
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
if (stack == null) {
return newRequestQueue(context, (BaseHttpStack) null);
}
return newRequestQueue(context, new BasicNetwork(stack));
}
复制代码
从上面的注释能够看出,HttpStack
是一个用于在 NetWork
中使用的对象,若是传入的 stack
不为 null,则会调用到 Volley.newRequestQueue(Context, Network)
,不然它一样会转调到 Volley.newRequestQueue(Context, BaseHttpStack)
:网络
/**
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
*
* @param context A {@link Context} to use for creating the cache dir.
* @param stack A {@link BaseHttpStack} to use for the network, or null for default.
* @return A started {@link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
// 建立 NetWork 对象
if (stack == null) {
// stack 为空则建立一个Stack,而后再建立 NetWork
// 高版本下,HttpStack 使用的是 HurlStack,低版本下使用 HttpClientStack
if (Build.VERSION.SDK_INT >= 9) {
network = new BasicNetwork(new HurlStack());
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
// At some point in the future we ll move our minSdkVersion past Froyo and can
// delete this fallback (along with all Apache HTTP code).
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info =
context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
network =
new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
network = new BasicNetwork(stack);
}
return newRequestQueue(context, network);
}
复制代码
这个方法主要作的事情就是根据 stack
建立 netWork
对象。app
在 stack
为空时,对于高于 9 的 SDK 版本,使用 HurlStack
,而对于低于它的版本则使用 HttpClientStack
。根据上面的注释能够看出这样作的缘由:由于在 SDK 9 以前的 HttpUrlConnection
不是很可靠。(咱们能够推测在高版本 (SDK > 9)Volley 基于 HttpUrlConnection
实现,低版本则基于 HttpClient
实现。框架
另外这里可能会比较疑惑,NetWork
和 HttpStack
都是用来作什么的?这些问题咱们后面都会一一解决。
它最后一样调用到了 Volley.newRequestQueue(Context, Network)
:
private static RequestQueue newRequestQueue(Context context, Network network) {
final Context appContext = context.getApplicationContext();
// Use a lazy supplier for the cache directory so that newRequestQueue() can be called on
// main thread without causing strict mode violation.
DiskBasedCache.FileSupplier cacheSupplier =
new DiskBasedCache.FileSupplier() {
private File cacheDir = null;
@Override
public File get() {
if (cacheDir == null) {
cacheDir = new File(appContext.getCacheDir(), DEFAULT_CACHE_DIR);
}
return cacheDir;
}
};
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheSupplier), network);
queue.start();
return queue;
}
复制代码
首先根据 Context
获取到了应用缓存文件夹并建立 Cache
文件。这里有个比较小的细节,为了在 Application 调用 newRequestQueue
同时又不被 StrictMode 有关文件操做相关的规则所影响,Volley 中使用了一个 FileSupplier
来对 File
进行包装,它采用了一个懒建立的思路,只有用到的时候才建立对应的 cacheDir
。
以后构造了 RequestQueue
,调用了其 start
方法并对其返回。能够看出来,Volley
是一个 RequestQueue
的静态工厂。
RequestQueue
中维护了三个容器:两个 PriorityBlockingQueue
:mCacheQueue
与 mNetQueue
,以及一个 Set
:mCurrentRequests
。
mCacheQueue
:用于存放缓存的待请求的 Request
。mNetQueue
:用于存放等待发起的 Request
。mCurrentQueue
:用于存放当前正在进行请求的 Request
。咱们先来看看 RequestQueue
的构造函数:
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
复制代码
它转调到了另外一个构造函数,并传递了一个默认线程数 DEFAULT_NETWORK_THREAD_POOL_SIZE
,它表明了网络请求分派线程启动时的默认个数,默认值为 4。
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(
cache,
network,
threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
复制代码
这个构造函数建立了一个主线程的 Handler
并用它构建了一个 ExecutorDelivery
,关于 ExecutorDelivery
咱们后面再讨论,它是一个用于交付 Response 和 Error 信息的类。
后面转调的构造函数主要是进行一些赋值。
接着咱们看看 RequestQueue.start
,看看它是如何启动的:
/** Starts the dispatchers in this queue. */
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
的主要用途是启动该 Queue
中的 Dispatcher
。它的主要步骤以下:
stop
方法中止全部正在运行的 Dispatcher
CacheDispatcher
并启动。NetworkDispatcher
(默认为 4 个)并启动。能够看出来,每一个 RequestQueue
中共有 5 个 Dispatcher
,其中有 4 个 NetworkDispatcher
和 1 个 CacheDispatcher
。
咱们能够经过 RequestQueue.add
将一个 Request
入队,它会根据当前 Request
是否须要进行缓存将其加入 mNetworkQueue
或 mCacheQueue
(这里实际上 GET
请求首先会放入 mCacheQueue
,其他请求直接放入 mNetworkQueue
)
/**
* Adds a Request to the dispatch queue.
*
* @param request The request to service
* @return The passed-in request
*/
public <T> Request<T> add(Request<T> request) {
// Tag the request as belonging to this queue and add it to the set of current requests.
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// Process requests in the order they are added.
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
// If the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}
复制代码
咱们先看看 stop
作了什么:
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (final NetworkDispatcher mDispatcher : mDispatchers) {
if (mDispatcher != null) {
mDispatcher.quit();
}
}
}
复制代码
这里仅仅是对每一个 Dispatcher
调用了其 quit
方法。
RequestQueue
还有个 finish
方法,对应了 Request.finish
:
/**
* Called from {@link Request#finish(String)}, indicating that processing of the given request
* has finished.
*/
@SuppressWarnings("unchecked") // see above note on RequestFinishedListener
<T> void finish(Request<T> request) {
// Remove from the set of requests currently being processed.
synchronized (mCurrentRequests) {
mCurrentRequests.remove(request);
}
synchronized (mFinishedListeners) {
for (RequestFinishedListener<T> listener : mFinishedListeners) {
listener.onRequestFinished(request);
}
}
sendRequestEvent(request, RequestEvent.REQUEST_FINISHED);
}
复制代码
主要是将结束的 Request
从 mCurrentRequests
中移除,并调用外部注册的回调以及发送 REQUEST_FINISHED
事件。
接下来咱们看看 ExecutorDelivery
到底是作什么的
/** Delivers responses and errors. */
public class ExecutorDelivery implements ResponseDelivery {
private final Executor mResponsePoster;
/**
* Creates a new response delivery interface.
*
* @param handler {@link Handler} to post responses on
*/
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster =
new Executor() {
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
//...
}
复制代码
根据上面的注释能够看出 ExecutorDelivery
的主要做用是交付 Response 和 Error 信息。
它内部持有了一个名为 ResponsePoster
的 Executor
,每一个调用这个 Poster
的 execute
方法的 Runnable
都会经过 Handler.post
发送到主线程的 MessageQueue
中。
接着咱们看到它内部的方法:
@Override
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));
}
复制代码
能够看出来,它内部的方法主要是将 Response 信息和 Error 信息 post 到 MessageQueue
中,其中 request
和 response
会被包装为一个 ResponseDeliveryRunnable
。
ResponseDeliveryRunnable
是 ExecutorDelivery
的一个内部类,能够看到它的 run
方法:
@Override
public void run() {
// NOTE: If cancel() is called off the thread that we re currently running in (by
// default, the main thread), we cannot guarantee that deliverResponse()/deliverError()
// won t be called, since it may be canceled after we check isCanceled() but before we
// deliver the response. Apps concerned about this guarantee must either call cancel()
// from the same thread or implement their own guarantee about not invoking their
// listener after cancel() has been called.
// If this request has canceled, finish it and don t deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
// If this is an intermediate response, add a marker, otherwise we re done
// and the request can be finished.
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
// If we have been provided a post-delivery runnable, run it.
if (mRunnable != null) {
mRunnable.run();
}
}
复制代码
这里会根据 Request
、Response
的不一样状态调用 Request
中的不一样方法以对 Response 和 Error 的结果进行交付:
Request
被取消,调用 Request.finish
方法直接结束。Request.deliverResponse
方法反馈 Response
Request.deliverError
方法反馈 Error
postResponse
方法传递了一个 Runnbale
进来,则执行该 Runnable
。咱们接着来看到 NetworkDispatcher
,它继承自 Thread
,咱们先看到其 run
方法:
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
Thread.currentThread().interrupt();
return;
}
VolleyLog.e(
"Ignoring spurious interrupt of NetworkDispatcher thread; "
+ "use quit() to terminate it");
}
}
}
复制代码
它在不断循环调用 processRequest
方法:
// Extracted to its own method to ensure locals have a constrained liveness scope by the GC.
// This is needed to avoid keeping previous request references alive for an indeterminate amount
// of time. Update consumer-proguard-rules.pro when modifying this. See also
// https://github.com/google/volley/issues/114
private void processRequest() throws InterruptedException {
// Take a request from the queue.
Request<?> request = mQueue.take();
processRequest(request);
}
复制代码
这里首先从 mQuque
( RequestQueue
中的 NetQuque
)中取出了 Request
,虽然 NetworkDispacher
是多个同时执行,但因为使用了 BlockingQueue
所以不用考虑线程安全问题。
能够发现这是一种典型的生产者消费者模型,多个 NetworkDispatcher
不断地从 NetQueue
中取出 Request
并进行网络请求,用户就是网络请求的生产者,而 NetworkDispatcher
就是网络请求的消费者。
processRequest
方法继续调用了 processRequest(Request)
方法:
void processRequest(Request<?> request) {
long startTimeMs = SystemClock.elapsedRealtime();
// 发送 REQUEST_NETWORK_DISPATCH_STARTED 事件
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
try {
request.addMarker("network-queue-take");
// 若是这个 request 已经被取消,则 finish 它并通知 Listener Response 没有用
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
request.notifyListenerResponseNotUsable();
return;
}
addTrafficStatsTag(request);
// 调用 mNetwork.performRequest 发起同步请求拿到 Response
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// 若是返回了 304 而且咱们已经交付了 Reponse,则 finish 它并通知 Listener Response 没有用
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
request.notifyListenerResponseNotUsable();
return;
}
// 对 response 进行转换
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");
}
// 经过 ExecutorDelivery 对 Response 进行交付并将 request 标记为已交付
request.markDelivered();
mDelivery.postResponse(request, response);
// 通知 Listener 已得到 Response
request.notifyListenerResponseReceived(response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
// 交付 Error 信息并通知 Listener Response 没有用
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);
// 交付 Error 信息并通知 Listener Response 没有用
mDelivery.postError(request, volleyError);
request.notifyListenerResponseNotUsable();
} finally {
// 发送 REQUEST_NETWORK_DISPATCH_FINISHED 事件
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
}
}
复制代码
上面的代码比较长,咱们能够将其分为以下的步骤:
REQUEST_NETWORK_DISPATCH_STARTED
事件,表示请求已开始request
已经被取消,则 finish
它并通知 Listener Response
没有用,再也不继续进行mNetwork.performRequest
发起同步请求拿到 Response
Reponse
,则 finish
它并通知 Listener Response
没有用,再也不继续进行Response
进行转换Request
能够进行缓存,以 Request
为 key,Response
为 value 进行缓存ExecutorDelivery
对 Response
进行交付并将 Request
标记为已交付Response
Response
没有用,其中全部 Error 都须要转换成 VollyError
类。REQUEST_NETWORK_DISPATCH_FINISHED
事件,表示请求已结束从上面的步骤咱们能够获得一些信息:
Event
机制用于传送各类事件Network
类是网络请求真正的实现类。Response
有个转换的问题Response
缓存机制。CacheDispatcher
一样继承自 Thread
,咱们先看到其 run
方法:
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
Thread.currentThread().interrupt();
return;
}
VolleyLog.e(
"Ignoring spurious interrupt of CacheDispatcher thread; "
+ "use quit() to terminate it");
}
}
}
复制代码
它也是在不断地调用 processRequest
方法:
private void processRequest() throws InterruptedException {
// Get a request from the cache triage queue, blocking until
// at least one is available.
final Request<?> request = mCacheQueue.take();
processRequest(request);
}
复制代码
这里与 NetworkDispatcher
中同样,从 mCacheQueue
中取出待请求的 Request
,以后看到 processRequest(Request)
:
void processRequest(final Request<?> request) throws InterruptedException {
request.addMarker("cache-queue-take");
// 发送 Event
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);
try {
// 若 request 已取消,直接 finish 它
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
return;
}
// 经过 request 尝试获取 Entry
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
// 若缓存未命中,则将其放入 mNetworkQueue 等待进行网络请求
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 若是缓存过时,放入 mNetworkQueue 等待进行网络请求
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 缓存命中,转换并获取 Response
request.addMarker("cache-hit");
Response<?> response =
request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// 若是获得的 response 不须要刷新,直接交付 Response
mDelivery.postResponse(request, response);
} else {
// 若是缓存到期,则将当前 response 设为中间 Response,进行 Response 交付
// 当 Response 成功交付,则会将其放入 mNetworkQueue 等待网络请求
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(
request,
response,
new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
} else {
// request has been added to list of waiting requests
// to receive the network response from the first request once it returns.
mDelivery.postResponse(request, response);
}
}
} finally {
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
}
}
复制代码
代码比较长,它主要有如下的步骤:
Request
已取消,直接 finish
它。Request
尝试获取缓存的 Response
对应的 Entry
。mNetworkQueue
等待进行网络请求。mNetworkQueue
等待进行网络请求。Response
。Response
不须要刷新,直接交付 Response
。Response
发现缓存到期,则将当前 Response
设为中间 Response
,进行 Response
交付。此时传入了一个 Runnable
,当 Response
成功交付时,会将 Request
放入 mNetworkQueue
等待网络请求。简单点说就是,若是缓存命中且 Response
未过时,则直接将其交付,不然将其放入 mNetworkQueue
等待网络请求。
前面提到的不少机制都与 Request
有关,为了更好的理解,咱们暂时先不关心 Network
是如何发起网络请求的,让咱们先看看 Request
的组成。
Request
只是一个抽象类,它的几个实现以下:
StringRequest
:返回 String
的 Request
。JsonRequest
:JsonObjectRequest
和 JsonArrayRequest
的基类。JsonObjectRequest
:返回 JsonObject
的 Request
。JsonArrayRequest
:返回 JsonArray
的 Request
。ImageRequest
:返回图片的 Request
。ClearCacheRequest
:一个用来清空缓存的 Request
,并非用来进行网络请求的 Request
。要构建一个 Request
,咱们能够经过其构造函数,其中不一样的子类有不一样的构造函数,主要的不一样是体如今其传入的 Listener
的不一样,例如 StringRequest
的构造函数以下:
public StringRequest(int method, String url, Listener<String> listener, @Nullable ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
复制代码
它们都会调用 Request(method, url, errorListener)
的构造函数:
public Request(int method, String url, @Nullable Response.ErrorListener listener) {
mMethod = method;
mUrl = url;
mErrorListener = listener;
setRetryPolicy(new DefaultRetryPolicy());
mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
}
复制代码
若是想要建立一个 POST 请求并传入参数,须要重写它的 getParams
方法:
protected Map<String, String> getParams() throws AuthFailureError {
return null;
}
复制代码
取消一个 Request
十分简单,只须要将 mCanceled
置为 true 便可:
public void cancel() {
synchronized (mLock) {
mCanceled = true;
mErrorListener = null;
}
}
复制代码
Request
的 parseNetworkResponse
方法是一个抽象方法,须要不一样子类去具体实现。
例如 StringRequest
的实现以下:
@Override
@SuppressWarnings("DefaultCharset")
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
// Since minSdkVersion = 8, we can t call
// new String(response.data, Charset.defaultCharset())
// So suppress the warning instead.
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
复制代码
很是简单,根据 Response.data
转化为了对应的 String
。
Response
的交付方法 deliverResponse
是一个抽象方法,须要不一样子类去具体实现,它主要作的事就是调用 Listener
的 onResponse
方法,并传入转换后的对象。
例如 StringRequest
的实现以下:
@Override
protected void deliverResponse(String response) {
Response.Listener<String> listener;
synchronized (mLock) {
listener = mListener;
}
if (listener != null) {
listener.onResponse(response);
}
}
复制代码
Error 的交付在 Request
中进行了实现,也很是简单,实际上就是调用 ErrorListener
的 onErrorResponse
方法:
public void deliverError(VolleyError error) {
Response.ErrorListener listener;
synchronized (mLock) {
listener = mErrorListener;
}
if (listener != null) {
listener.onErrorResponse(error);
}
}
复制代码
/**
* Notifies the request queue that this request has finished (successfully or with error).
*
* <p>Also dumps all events from this request s event log; for debugging.
*/
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()) {
// If we finish marking off of the main thread, we need to
// actually do it on the main thread to ensure correct ordering.
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());
}
}
复制代码
主要是调用了 RequestQueue.finish
方法,它会将当前 Request
从正在执行的 Request
队列移除。
在 Response
被缓存以前会调用 Request.shouldCache
判断是否须要缓存,
/** Whether or not responses to this request should be cached. */
// TODO(#190): Turn this off by default for anything other than GET requests.
private boolean mShouldCache = true;
复制代码
能够看到,除了 GET
请求,其他请求方式都不容许缓存。
咱们再看看存在缓存中的 key 是如何经过 Request
转换而得:
public String getCacheKey() {
String url = getUrl();
// If this is a GET request, just use the URL as the key.
// For callers using DEPRECATED_GET_OR_POST, we assume the method is GET, which matches
// legacy behavior where all methods had the same cache key. We can t determine which method
// will be used because doing so requires calling getPostBody() which is expensive and may
// throw AuthFailureError.
// TODO(#190): Remove support for non-GET methods.
int method = getMethod();
if (method == Method.GET || method == Method.DEPRECATED_GET_OR_POST) {
return url;
}
return Integer.toString(method) + '-' + url;
}
复制代码
因为新版 Volley 中只支持 GET
请求进行缓存,所以 Request
是以 url 做为缓存的 key。
咱们暂时先不关心 Network
的具体实现,让咱们先看看 Event
发出后作了什么。
调用 sendEvent
后,转调到了 RequestQueue.sendRequestEvent
中:
void sendRequestEvent(Request<?> request, @RequestEvent int event) {
synchronized (mEventListeners) {
for (RequestEventListener listener : mEventListeners) {
listener.onRequestEvent(request, event);
}
}
}
复制代码
能够看出,咱们的用户能够向 RequestQueue
中注册一个 RequestEventListener
来监听 Request
相关的 Event
。
相比 Request
,Response
就简单了不少(感受不少 Response
的功能放在了 Request
),里面主要是携带了一些请求结束后的相关信息。
public class Response<T> {
/** Callback interface for delivering parsed responses. */
public interface Listener<T> {
/** Called when a response is received. */
void onResponse(T response);
}
/** Callback interface for delivering error responses. */
public interface ErrorListener {
/**
* Callback method that an error has been occurred with the provided error code and optional
* user-readable message.
*/
void onErrorResponse(VolleyError error);
}
/** Returns a successful response containing the parsed result. */
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
return new Response<>(result, cacheEntry);
}
/**
* Returns a failed response containing the given error code and an optional localized message
* displayed to the user.
*/
public static <T> Response<T> error(VolleyError error) {
return new Response<>(error);
}
/** Parsed response, or null in the case of error. */
public final T result;
/** Cache metadata for this response, or null in the case of error. */
public final Cache.Entry cacheEntry;
/** Detailed error information if <code>errorCode != OK</code>. */
public final VolleyError error;
/** True if this response was a soft-expired one and a second one MAY be coming. */
public boolean intermediate = false;
/** Returns whether this response is considered successful. */
public boolean isSuccess() {
return error == null;
}
private Response(T result, Cache.Entry cacheEntry) {
this.result = result;
this.cacheEntry = cacheEntry;
this.error = null;
}
private Response(VolleyError error) {
this.result = null;
this.cacheEntry = null;
this.error = error;
}
}
复制代码
从前面的分析中,咱们能够知道,真正的网络请求是经过 Network
类实现的,它是一个抽象类,只有一个子类 BaseNetwork
。
咱们主要关注它的 performRequest
方法:
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
// 不断循环
HttpResponse httpResponse = null;
byte[] responseContents = null;
List<Header> responseHeaders = Collections.emptyList();
try {
// 获取 Header
Map<String, String> additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
// 经过 httpStack.executeRequest 来同步执行网络请求
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// 若没有 Modified,则构建一个 NetworkResponse 并返回
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(
HttpURLConnection.HTTP_NOT_MODIFIED,
/* data= */ null,
/* notModified= */ true,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
}
// 将 response 的 header 和缓存的 entry 结合,变成新的 Headers
List<Header> combinedHeaders = combineHeaders(responseHeaders, entry);
return new NetworkResponse(
HttpURLConnection.HTTP_NOT_MODIFIED,
entry.data,
/* notModified= */ true,
SystemClock.elapsedRealtime() - requestStart,
combinedHeaders);
}
// 有的 Response 没有 content,所以须要对 content 进行判断
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} 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, statusCode);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
// 返回请求结果构建的 Response
return new NetworkResponse(
statusCode,
responseContents,
/* notModified= */ false,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode;
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
NetworkResponse networkResponse;
if (responseContents != null) {
networkResponse =
new NetworkResponse(
statusCode,
responseContents,
/* notModified= */ false,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED
|| statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
attemptRetryOnException(
"auth", request, new AuthFailureError(networkResponse));
} else if (statusCode >= 400 && statusCode <= 499) {
// Don t retry other client errors.
throw new ClientError(networkResponse);
} else if (statusCode >= 500 && statusCode <= 599) {
if (request.shouldRetryServerErrors()) {
attemptRetryOnException(
"server", request, new ServerError(networkResponse));
} else {
throw new ServerError(networkResponse);
}
} else {
// 3xx? No reason to retry.
throw new ServerError(networkResponse);
}
} else {
attemptRetryOnException("network", request, new NetworkError());
}
}
}
}
复制代码
这里的代码很是长,主要是下面的步骤:
mBaseHttpStack
进行网络请求Modified
,则将返回的 Headers 与缓存的信息结合构建 NetworkResponse
并返回。NetworkResponse
并返回。Error
或 Response
并返回。HttpStack
是咱们真正执行网络请求的类,它有两个实现:HurlStack
以及 HttpClientStack
,前者基于 HttpUrlConnection
实现,后者基于 HttpClient
实现。
因为 HttpClient
已经被完全抛弃,而且目前几乎已经不存在 SDK 9 如下的机器,所以咱们只须要分析 HurlStack
便可,咱们看到其 executeRequest
方法:
@Override
public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap<String, String> map = new HashMap<>();
map.putAll(additionalHeaders);
// Request.getHeaders() takes precedence over the given additional (cache) headers).
map.putAll(request.getHeaders());
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);
HttpURLConnection connection = openConnection(parsedUrl, request);
boolean keepConnectionOpen = false;
try {
for (String headerName : map.keySet()) {
connection.setRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);
// Initialize HttpResponse with data from the HttpURLConnection.
int responseCode = connection.getResponseCode();
if (responseCode == -1) {
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
if (!hasResponseBody(request.getMethod(), responseCode)) {
return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields()));
}
// Need to keep the connection open until the stream is consumed by the caller. Wrap the
// stream such that close() will disconnect the connection.
keepConnectionOpen = true;
return new HttpResponse(
responseCode,
convertHeaders(connection.getHeaderFields()),
connection.getContentLength(),
new UrlConnectionInputStream(connection));
} finally {
if (!keepConnectionOpen) {
connection.disconnect();
}
}
}
复制代码
这里没什么难度,就再也不详细介绍,主要是调用了 HttpUrlConnection
的 API 进行网络请求。
Volley 的缓存机制基于 Cache
这个接口实现,它对外暴露了 put
、get
等常见的缓存操做接口。默认状况下采用基于磁盘的缓存 DiskBasedCache
。
这一块主要是一些对文件的读取与写入,暂时就不研究了,有兴趣的读者能够自行阅读。
为了在 Application 调用 newRequestQueue
同时又不被 StrictMode 有关文件操做相关的规则所影响,Volley 中使用了一个 FileSupplier
来对 File
进行包装,它采用了一个懒建立的思路,只有用到的时候才建立对应的 cacheDir
文件
RequestQuque
维护了三个队列,分别是待请求缓存队列、待网络请求队列以及正在请求队列。
RequestQueue
默认状况下维护了 4 个 NetworkDispatcher
以及 1 个 CacheDispatcher
,它们都是继承自 Thread
,经过异步进行网络请求的方式从而提升请求效率。
请求的成功或失败都会经过 ExecutorDelivery
进行交付,而后经过 Request
通知到各个 Listener
。
存在一套缓存机制,以 Request
为 Key,以 Response
为 Value。只有 GET 请求须要进行缓存,全部 GET 请求会首先被放入缓存队列 mCacheQueue
,当缓存未命中或缓存过时时,才会被放入 mNetQueue
进行网络请求。
Network
是一个对网络请求的执行进行包装的类,它主要负责了 Response
的转换以及对重试的支持。
HttpStack
是真正执行网络请求的类,它在高于 SDK 9 的版本下会基于 HttpUrlConnection
进行网络请求,不然会基于 HttpClient
进行网络请求。
Cache
实现了 Volley 的缓存机制,默认状况下采用基于磁盘的缓存 DiskBasedCache
。
Volley 虽没有像 OkHttp 那样灵活的拦截器机制,但提供了不少 Listener
供外界对请求过程进行监听。