前言
前面解析了Retrofit和OkHttp这两个框架的源码,提到网络框架,肯定少不了Volley这位老前辈,想曾经的项目用的可都是Volley,每个框架都有其适用的场景,只是随着时间的更迭,逐渐被替代。 那这次顺便也解析下Volley框架的源码,这里做个笔记
本篇的Volley版本基于 1.2.0-SNAPSHOT
1.首先看下Volley的基本使用
//第1步.创建RequestQueue(请求队列)
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
//第2步.创建所需的Request(请求),这里是创建StringRequest
StringRequest mStringRequest =
new StringRequest(Request.Method.GET, "http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.i("wangshu", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("wangshu", error.getMessage(), error);
}
});
//第3步.将请求添加进请求队列中
mQueue.add(mStringRequest);
2.从Volley的基本使用API入手其源码:
a. 首先看下创建RequestQueue的代码,由Volley.newRequestQueue开始
public class Volley {
public static RequestQueue newRequestQueue(Context context) {
//调用下面标注1的newRequestQueue
return newRequestQueue(context, (BaseHttpStack) null);
}
//标注1
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
//Android版本大于2.3,则创建基于HttpUrlConnection的HurlStack
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) {
}
//Android版本小于2.3,则创建基于HttpClient的HttpClientStack
network =
new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
//stack != null的情况
network = new BasicNetwork(stack);
}
//调用下面标注2的newRequestQueue
return newRequestQueue(context, network);
}
//标注2
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;
}
}
结合代码和注释,Volley.newRequestQueue主要做了两件事
- 判断Android的系统版本是否大于2.3; Android版本大于或等于2.3,则创建基于HttpUrlConnection的HurlStack。 Android版本小于2.3,则创建基于HttpClient的HttpClientStack
- 创建请求队列RequestQueue,并调用其start函数,最后返回RequestQueue
接着进去RequestQueue的start 函数
public class RequestQueue {
public void start() {
//将当前正在执行的线程全部中断
stop();
//创建缓存线程并且启动它
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// mDispatchers数组默认动态初始化长度为4,所以网络执行线程默认创建4条
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher =
new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
}
在RequestQueue的start 函数中,初始化一个缓存调度线程(CacheDispatcher)和4个( 默认情况下 ) 网络调度线程(NetworkDispatcher),所以Volley默认情况下会在后台开启5个线程。线程都初始化之后,分别调用其start方法开启线程
b. 接着看下第2步创建的StringRequest类,看下StringRequest两个核心的函数
public class StringRequest extends Request<String> {
//deliverResponse主要负责回调响应数据
@Override
protected void deliverResponse(String response) {
Response.Listener<String> listener;
synchronized (mLock) {
listener = mListener;
}
if (listener != null) {
listener.onResponse(response);
}
}
//负责解析响应数据
@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));
}
}
可以看到StringRequest类的代码很简洁,deliverResponse函数负责将响应结果进行回调,parseNetworkResponse函数解析响应数据为Response实例,这里先记住deliverResponse和parseNetworkResponse这两个函数,后面会再碰到这个函数
c.将请求添加进请求队列中
public class RequestQueue {
public <T> Request<T> add(Request<T> request) {
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// Process requests in the order they are added.
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
//发送request生命周期事件
sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
/**
* 如果这个request不支持缓存,那将直接添加到网络请求队列中,并返回这个request
* request.shouldCache() 默认为true,即开启缓存
*/
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
//request支持缓存,则添加到缓存队列中
mCacheQueue.add(request);
return request;
}
}
在add函数中主要通过request.shouldCache()判断是否支持缓存,不支持缓存则将request添加进mNetworkQueue(网络请求队列),支持缓存的话则将request添加到mCacheQueue(缓存队列); request.shouldCache( )默认情况下为true,即开启缓存
在上面的代码中,可以了解到:
- 默认情况下,是将请求添加到缓存队列中
- Volley中主要维护了了1个缓存调度线程(CacheDispatcher),和4个(默认情况下) 网络调度线程(NetworkDispatcher)
请求添加到缓存队列,我们就从缓存调度线程(CacheDispatcher)入手
3.CacheDispatcher的工作流程
CacheDispatcher继承自Thread,那核心自然是run函数.
public class CacheDispatcher extends Thread {
@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");
}
}
}
}
在run函数中开启了死循环,不断执行processRequest函数
private void processRequest() throws InterruptedException {
//从缓存队列中取出请求
final Request<?> request = mCacheQueue.take();
processRequest(request);
}
@VisibleForTesting
void processRequest(final Request<?> request) throws InterruptedException {
request.addMarker("cache-queue-take");
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);
try {
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
return;
}
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
//返回true则表示之前有执行过该请求,属于重复请求
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// If it is completely expired, just send it to the network.
//true表示 缓存已到有效期
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
//返回true则表示之前有执行过该请求,属于重复请求
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response =
request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
/**
* 判断缓存的数据是否解析成功
* JsonObjectRequest的parseNetworkResponse函数中,解析失败的话会对Response类的error变量设置值
* response.isSuccess()则是判断error变量是否为null
*/
if (!response.isSuccess()) { //缓存数据解析失败的情况
request.addMarker("cache-parsing-failed");
mCache.invalidate(request.getCacheKey(), true);
request.setCacheEntry(null);
//返回true则表示之前有执行过该请求,属于重复请求
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
//缓存是否需要更新
if (!entry.refreshNeeded()) {//不需要更新缓存的情况
// Completely unexpired cache hit. Just deliver the response.
//mDelivery的默认实现类是ExecutorDelivery,在RequestQueue类的构造函数中赋值的
//在ExecutorDelivery的postResponse函数中将子线程切换到主线程,并回调给Response.Listener的onResponse()方法
mDelivery.postResponse(request, response);
} else {//需要更新缓存的情况
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
//返回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) {
// Restore the interrupted status
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.
//将数据回调给主线程 (Response.Listener的onResponse()方法 )
mDelivery.postResponse(request, response);
}
}
} finally {
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
}
}
processRequest函数中大致做了如下几个判断:
- processRequest函数从缓存队列中取出请求,然后判断该请求是否被取消?
- 如果取消,则直接中止该函数;
- 如果没有取消,则判断该请求是否有对应的缓存?
- 如果没有缓存,则判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
- 如果有缓存,则判断该缓存是否过期?
- 如果已过期,则判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
- 如果未过期,则解析缓存的数据,接着判断缓存数据是否解析成功?
- 如果解析失败,则设置缓存无效,并判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
- 如果解析成功,接着判断该缓存是否需要更新?
- 如果不需要更新,则将第4步中缓存数据解析的结果回调给主线程
- 如果需要更新,则判断该请求是否已执行过?
- 如果该请求已执行过,将第4步中缓存数据解析的结果回调给主线程
- 如果该请求未执行过,将第4步中缓存数据解析的结果回调给主线程,并将请求添加到网络请求队列中
processRequest函数中调用request.parseNetworkResponse()解析缓存的数据, request是从缓存队列中取出的,所以这个request就是一开始API中调用mQueue.add() 添加到缓存队列的StringRequest,而StringRequest类的parseNetworkResponse函数在上面已经提到,是用于将响应数据解析为Response实例的
4.NetworkDispatcher的工作流程
NetworkDispatcher同样继承自Thread,run函数同样是开启了死循环,不断执行processRequest函数
public class NetworkDispatcher extends Thread {
private void processRequest() throws InterruptedException {
//从网络队列中取出请求
Request<?> request = mQueue.take();
processRequest(request);
}
@VisibleForTesting
void processRequest(Request<?> request) {
long startTimeMs = SystemClock.elapsedRealtime();
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
request.notifyListenerResponseNotUsable();
return;
}
addTrafficStatsTag(request);
// Perform the network 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.
//如果服务端响应码是304 && 该请求已经请求过,则取消该次请求
//在下面的代码中request.markDelivered()会将该请求设置为已请求状态
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
request.notifyListenerResponseNotUsable();
return;
}
// Parse the response here on the worker thread.
//在工作线程上解析服务端的响应数据
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
//缓存数据
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
//和CacheDispatcher同一个mDelivery,mDelivery默认为ExecutorDelivery
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();
} finally {
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
}
}
}
processRequest函数从网络队列中取出请求,判断该请求是否被取消,取消的话直接中止该函数,
没有取消则发起网络请求获取响应数据,判断响应码是不是304和该请求是否已请求过,
如果两个条件都满足,中断该函数;否则解析响应数据, 接着判断是否进行缓存,
最后将缓存数据解析的结果回调给主线程
核心的点在于
- 调用mNetwork.performRequest(request)发起网络请求
- 调用request.parseNetworkResponse(networkResponse)解析响应的数据,这个在CacheDispatcher的工作流程已经提到过
而mNetwork不就是一开始在Volley类的newRequestQueue创建的BasicNetwork实例,接着看BasicNetwork类的performRequest函数发起网络请求的流程
5.发起网络请求的工作流程
public class BasicNetwork implements Network {
@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 {
// Gather headers.
Map<String, String> additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
//底层使用HttpUrlConnection或HttpClient发起网络请求
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// Handle cache validation.
//响应码为304的情况
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);
}
// Combine cached and response headers so the response will be complete.
List<Header> combinedHeaders = combineHeaders(responseHeaders, entry);
return new NetworkResponse(
HttpURLConnection.HTTP_NOT_MODIFIED,
entry.data,
/* notModified= */ true,
SystemClock.elapsedRealtime() - requestStart,
combinedHeaders);
}
// Some responses such as 204s do not have content. We must check.
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();
}
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.executeRequest发起网络请求,mBaseHttpStack则是在Volley类的newRequestQueue函数创建的HurlStack实例或HttpClientStack实例,HttpClientStack类主要封装了HttpClient的网络请求操作,在Android2.3版本之前才使用HttpClientStack这个类,所以这个类基本淘汰了. 而HurlStack类是对HttpURLConnection的网络请求做了封装
6. 将响应结果进行回调
在NetworkDispatcher和CacheDispatcher会将响应数据解析成功的结果,回调给主线程,这里面是怎么回调到主线程的? 可以看到回调主要是调用mDelivery.postResponse(request, response)这行代码,其中的mDelivery是从RequestQueue类传递过来的,看RequestQueue的构造函数
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(
cache,
network,
threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(
Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
mDelivery就是在RequestQueue的构造函数中创建的, 其实例是ExecutorDelivery,这里注意下创建ExecutorDelivery实例传入的参数是持有主线程Looper的Handler, mDelivery是在RequestQueue类的start函数中创建CacheDispatcher和NetworkDispatcher时传递过去的,接着看ExecutorDelivery的postResponse函数做了什么?
public class ExecutorDelivery implements ResponseDelivery {
private final Executor mResponsePoster;
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);
}
};
}
@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));
}
}
核心在于mResponsePoster.execute()这句代码,在其构造函数中创建mResponsePoster,可以看到mResponsePoster是个实现Executor的匿名内部类, 而在上面我们看到Handler持有的Looper来源于主线程, execute函数只有handler.post(command) 这句代码,因此mResponsePoster主要是将子线程切换到主线程.
那上面既然主要是将子线程切换到主线程,是不是缺少了线程这个主角,这里的ResponseDeliveryRunnable就是我们的线程,当执行了上面的mResponsePoster.execute()这行代码,默认就启动了线程的run函数,看ResponseDeliveryRunnable的run函数.
private static class ResponseDeliveryRunnable implements Runnable {
@Override
public void run() {
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();
}
}
}
从上面可以知道,这个run函数是执行在主线程的,这也就解释了回调给我们的响应结果为什么是在主线程的,
run函数首先判断请求是否取消,取消了就直接中止该run函数,
没取消则判断响应数据是否解析成功,解析成功则调用成功的回调函数,解析失败则调用失败的回调函数,
这里的mRequest.deliverResponse则是上面提到的StringRequest类的deliverResponse函数,负责将响应数据回调到主线程
疑问出现,这里的mRunnable有什么用呢? 而响应数据又是怎么判断解析成功的?
mRunnable有什么用呢?
在上面的CacheDispatcher的工作流程中,有1个判断是该缓存是否需要更新,先看这部分的代码
void processRequest(final Request<?> request) throws InterruptedException {
//...省略无关代码
mDelivery.postResponse(
request,
response,
new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
});
//...省略无关代码
}
可以看到调用了ExecutorDelivery的postResponse函数,并创建Runnable的匿名内部类作为参数传递,而在run函数中是将请求添加到网络请求队列中,因此ExecutorDelivery的mRunnable主要是将请求添加到网络请求队列中。 因此,需要更新缓存的情况下,CacheDispatcher是先将满足条件的缓存回调给主线程,接着开启线程将请求添加到网络请求队列中,之后的更新缓存的活就交给NetworkDispatcher咯
响应数据又是怎么判断解析成功的?
上面是调用mResponse.isSuccess()进行判断解析是否成功的,在isSuccess函数中判断error == null,也就是error变量为null,返回true则解析成功,error变量是在私有的构造函数中进行赋值的,因此唯一设置error变量的入口只能是Response类的success函数和error函数
public class Response<T> {
public boolean isSuccess() {
return error == null;
}
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
return new Response<>(result, cacheEntry);
}
public static <T> Response<T> error(VolleyError error) {
return new Response<>(error);
}
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;
}
}
接着看下解析的过程,看到StringRequest类的parseNetworkResponse函数
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
在StringRequest类的parseNetworkResponse函数只有success的操作,因此如果请求是StringRequest实例,解析操作都将是成功的,接着看下请求体是json对象的情况,也就是看下JsonObjectRequest类的parseNetworkResponse函数
public class JsonObjectRequest extends JsonRequest<JSONObject> {
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString =
new String(
response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
return Response.success(
new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
看到这里是不是一切都了然咯,当捕获到异常的情况下,就会调用Response类的error函数,由此error值不为null。
7.场景
Volley的源码看得最深刻的就是while循环,在没有请求的情况下,不断循环的确浪费资源,还有默认开启缓存,不适合大文件流操作的情况. 但Volley也不是没有优点,简单轻巧、适合数据小的场景, 再回首下图