** 本文仅对Volley中关于Http Request部分的一些简单用例做解析 **
源码目录树
首先,用脚本生成了该项目源码的目录树:
[android]
┗━[volley]
┣━AuthFailureError.java
┣━Cache.java
┣━CacheDispatcher.java
┣━DefaultRetryPolicy.java
┣━ExecutorDelivery.java
┣━InternalUtils.java
┣━Network.java
┣━NetworkDispatcher.java
┣━NetworkError.java
┣━NetworkResponse.java
┣━NoConnectionError.java
┣━ParseError.java
┣━RedirectError.java
┣━Request.java
┣━RequestQueue.java
┣━Response.java
┣━ResponseDelivery.java
┣━RetryPolicy.java
┣━ServerError.java
┣━TimeoutError.java
┣━[toolbox]
┃ ┣━AndroidAuthenticator.java
┃ ┣━Authenticator.java
┃ ┣━BasicNetwork.java
┃ ┣━ByteArrayPool.java
┃ ┣━ClearCacheRequest.java
┃ ┣━DiskBasedCache.java
┃ ┣━HttpClientStack.java
┃ ┣━HttpHeaderParser.java
┃ ┣━HttpStack.java
┃ ┣━HurlStack.java
┃ ┣━ImageLoader.java
┃ ┣━ImageRequest.java
┃ ┣━JsonArrayRequest.java
┃ ┣━JsonObjectRequest.java
┃ ┣━JsonRequest.java
┃ ┣━NetworkImageView.java
┃ ┣━NoCache.java
┃ ┣━PoolingByteArrayOutputStream.java
┃ ┣━RequestFuture.java
┃ ┣━StringRequest.java
┃ ┗━Volley.java
┣━VolleyError.java
┗━VolleyLog.java
可以看出,Volley源码放置得较为杂乱,不同功能模块的类并没有归到不同的包中。相比之下UIL的源码结构较为规范和合理。
从常用case入手,推断其项目架构
官网上给出的最简单的使用例子如下所示:
final TextView mTextView = (TextView) findViewById(R.id.text);
...
// 1. 新建一个Queue
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// 2. 新建一个Request,写好listener
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// 3. 将Request放到Queue里面执行
queue.add(stringRequest);
结合下面这张图:
我们可以大致了解Volley的使用方法(见注释)和内部结构。下面就这个usecase展开进行源码级别的简述。
Volley类
Volley类提供了4个静态方法来方便用户新建Queue。其中:
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}
一句最终会调用:
// 传入 context,stack=null,maxDiskCacheBytes=-1
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0"; //1. 设置userAgent
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) { //2. 选择用哪个httpclient
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));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network); //3. 新建Queue
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();// 4. 传入Queue
return queue;
}
值得注意的是:
- Volley会根据SDK的version来决定使用java.net.HttpURLConnection(Build.VERSION.SDK_INT >= 9)还是org.apache.http.client.HttpClient
- 新建Queue后,Queue马上会被start。
- stack类负责发送request(com.android.volley.Request)和获取response(org.apache.http.HttpResponse),network类负责分析和处理response,包装成NetworkResponse(com.android.volley.NetworkResponse)。
我们首先忽略掉network相关的细节,看一下queue的实现和request的调度策略。
RequestQueue
先来看一下RequestQueue的构造方法:
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
调用:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
这里出现了一个新面孔ExecutorDelivery,根据字面意思可以猜测它是负责将请求的结果分发到主线程上,或者在主线程上执行回调(listener)。继续调用:
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
这里又出现了一个新面孔NetworkDispatcher。留意到threadPoolSize这个数组长度参数的字面意义,结合上面的Volley架构图,猜想NetworkDispatcher是一个work thread,循环等待并通过network执行在Queue上的request。
RequestQueue被实例化后,便调用其start()方法:
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();
}
}
相应地有:
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
这里的逻辑很简单:
- 开始之前停止所有旧的任务(即interrupt所有worker thread)。
- 启动一个负责cache的worker thread。
- 启动n个负责network的worker thread。
- worker thread开始不断地等待来自Queue的request。
Request
接下来执行queue.add(stringRequest);
,一个request被加入到queue中,代码如下所示:
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"); // marker用来指示request当前的状态,实际上是用来打log
// If the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// Insert request into stage if there's already a request with the same cache key in flight.
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
// There is already a request in flight. Queue up.
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request<?>>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
这里的逻辑是:
- 对新加进来的request进行一些设置。
- 如果不需要cache,那么把request直接加到network queue中。
- 根据key检查request是否正在执行。如果是,则将其放入到waiting链表中。猜想当request完成的时候会调用某个方法将key在waiting链表中删除,然后依次执行waiting的request。如果否,则将其加入cache queue中。
CacheDispatcher
假设该uri访问是第一次执行,那么对应的request会被放到cache queue中。cache worker thread(cache dispatcher)发现cache queue中存在request,会马上将其dequeue并执行。我们来看一下CacheDispatcher的run方法:
public class CacheDispatcher extends Thread {
...
private final Cache mCache; // 一开始传入了“new DiskBasedCache(cacheDir)”
...
public void quit() {
mQuit = true;
interrupt();
}
@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();
Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null; //确保最后一个request做完后能及时回收内存。
try {
// Take a request from the queue.
request = mCacheQueue.take(); // 堵塞
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return; // 退出点
}
continue;
}
try {
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// miss cache则直接将request放到network queue中
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
// cache 过期了,直接将request放到network queue中
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// 将cache中的data包装成一个response
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// cache不需要刷新,直接将response交给delivery
mDelivery.postResponse(request, response);
} else {
// cache需要刷新。现将旧的内容返回,同时将request放进network queue。
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
}
}
}
}
接下来看一下mDelivery.postResponse这个方法。
ExecutorDelivery
从上文得知,mDelivery是一个ExecutorDelivery的实例(在新建RequestQueue时传入)。
ExecutorDelivery的初始化代码如下所示:
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster = new Executor() { // java.util.concurrent.Executor;
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
关于java.util.concurrent.Executor可以看这篇文章,这里就不展开了。
postResponse代码如下所示:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered(); //标记为已分发
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); // 在初始化时传入的handler中执行ResponseDeliveryRunnable
}
ResponseDeliveryRunnable是ExecutorDelivery的一个子类,负责根据request的不同结果调用对应的listener方法:
@SuppressWarnings("rawtypes")
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.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery"); // 会调用 RequestQueue的finish方法
return;
}
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result); //调用 listener的onResponse(response)
} 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();
}
}
}
接下来我们回头看看NetworkDispatcher对network queue的处理。
NetworkDispatcher
NetworkDispatcher的源码如下所示:
public class NetworkDispatcher extends Thread {
private final Network mNetwork; // BasicNetwork实例
...
private final BlockingQueue<Request<?>> mQueue; // network queue
...
public void quit() {
mQuit = true;
interrupt();
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void addTrafficStatsTag(Request<?> request) { // 方便统计Volley的网络流量
...
}
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<?> request;
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
//1. 堵塞读取network queue中的request
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
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");
continue;
}
addTrafficStatsTag(request);
//2. 在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.
if (networkResponse.notModified && request.hasHadResponseDelivered()) { // 304表示资源未被修改
request.finish("not-modified");
continue;
}
//3. 将NetworkResponse转成Response
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) {
// 4. Response放到cache中
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
//5. 通过Delivery回调结果
request.markDelivered();
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} 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);
}
}
}
private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}
}
NetworkDispatcher的处理流程和CacheDispatcher差不多,见注释。TrafficStats的介绍可以看这里。
上述代码的关键在于mNetwork.performRequest(request)
和request.parseNetworkResponse(networkResponse)
这两个调用。
Network
Network是一个接口,只有一个performRequest(Request<?> request)
方法:
public interface Network {
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
本文例子中Network的实现类是BasicNetwork:
public class BasicNetwork implements Network {
protected static final boolean DEBUG = VolleyLog.DEBUG;
private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
private static int DEFAULT_POOL_SIZE = 4096;
protected final HttpStack mHttpStack;
protected final ByteArrayPool mPool;
public BasicNetwork(HttpStack httpStack) {
// If a pool isn't passed in, then build a small default pool that will give us a lot of
// benefit and not use too much memory.
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
}
...
}
注意到BasicNetwork的两个关键的成员:mHttpStack和mPool,和对apache依赖:
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
可我们先来看一下performRequest()
的执行流程:
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
// 依赖 org.apache.http.HttpResponse
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// 1. 生成header
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
// 2. 通过httpstack发起请求。注意‘发起请求’这个动作不在request中进行,request只是保存着请求的信息。
httpResponse = mHttpStack.performRequest(request, headers);
// 3. 获得请求结果的一些信息
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// 4. 通过statusCode(304)来判断是否可以直接使用cache
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);
}
// 从cache中取出data,返回新的NetworkResponse
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
entry.responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// 5. 通过statusCode通过判断是否需要重定向
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
String newUrl = responseHeaders.get("Location");
request.setRedirectUrl(newUrl);
}
// 6. 取出reponse中的data,为字节数组
// Some responses such as 204s do not have content. We must check.
if (httpResponse.getEntity() != null) {
// 通过entityToBytes从outputstream中读取数据,throws IOException
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);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
// 7. 如果entityToBytes方法throw了IOException
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
} else {
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
}
// 如果reponseContent有数据
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
// 那么根据statusCode执行重试
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
attemptRetryOnException("redirect",
request, new RedirectError(networkResponse));
} else {
// TODO: Only throw ServerError for 5xx status codes.
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(e);
}
}
}
}
attemptRetryOnException()
代码如下所示:
private static void attemptRetryOnException(String logPrefix
, Request<?> request,
VolleyError exception) throws VolleyError {
RetryPolicy retryPolicy = request.getRetryPolicy();
int oldTimeout = request.getTimeoutMs();
try {
// 关键语句
retryPolicy.retry(exception);
} catch (VolleyError e) {
request.addMarker(
String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
throw e;
}
request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
}
RetryPolicy是一个接口:
public interface RetryPolicy {
public int getCurrentTimeout();
public int getCurrentRetryCount();
public void retry(VolleyError error) throws VolleyError;
}
如没有特殊指定,request中的RetryPolicy为DefaultRetryPolicy,其retry方法实现如下:
public void retry(VolleyError error) throws VolleyError {
mCurrentRetryCount++;
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
if (!hasAttemptRemaining()) {
throw error;
}
}
如果还没超出重试次数上限,那么不会抛出异常,并返回到performRequest()的while循环中。接下来分析一下BaseNetwork的entityToBytes()方法:
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
// 1. 新建PoolingByteArrayOutputStream
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
byte[] buffer = null;
try {
InputStream in = entity.getContent();
if (in == null) {
throw new ServerError();
}
// 2. 在字节池中取出1024字节buffer
buffer = mPool.getBuf(1024);
int count;
// 3. 从entity的inputStream中读出数据到buffer
while ((count = in.read(buffer)) != -1) {
// 将buffer写到PoolingByteArrayOutputStream中
bytes.write(buffer, 0, count);
}
// 4. 将所有数据返回
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
entity.consumeContent();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
// 5. 归还buffer到字节池
mPool.returnBuf(buffer);
bytes.close();
}
}
执行步骤见代码注释。这里不对ByteArrayPool类和PoolingByteArrayOutputStream展开。
HttpStack
HttpStack是一个接口,仅负责将request发送出去:
public interface HttpStack {
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}
从最开始的对Volley类的分析可知,SDK version > 9的情况下使用HurlStack(java.net.HttpURLConnection),否则使用HttpClientStack(org.apache.http.client.HttpClient)。
stack各自实现了performRequest()方法,在内部正式发起了http请求。具体的用法参考各自的api文档,这里不详细展开了。
Request
Request类主要是保存着该次请求的参数和该次请求当前的状态,本身不含有请求相关的行为:
public abstract class Request<T> implements Comparable<Request<T>> {
...
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;
}
...
private final int mMethod;
private final String mUrl;
private String mRedirectUrl;
private String mIdentifier;
private final int mDefaultTrafficStatsTag;
private Response.ErrorListener mErrorListener;
private Integer mSequence;
private RequestQueue mRequestQueue;
private boolean mShouldCache = true;
private boolean mCanceled = false;
private boolean mResponseDelivered = false;
private RetryPolicy mRetryPolicy;
...
}
下面再来分析一下request.parseNetworkResponse(networkResponse)
这个方法。以StringRequest为例:
@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));
}
可以看到它只是简单地将data转换成string,然后返回一个success的response。
而JsonObjectRequest的实现如下:
@Override
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));
}
}
它现将data转换成string,然后再生成一个JSONObject返回。
总结
综上,Volley的大致框架如下所述:
- 一个RequestQueue中包含两个内部queue,分别是cache queue和network queue。还有一个cache dispatcher和n个network dispatcher,它们都继承成于Thread,分别负责执行缓存和网络请求。还有一个delivery,负责分发请求结果。
- cache dispatcher在独立的线程上运行。cache dispatcher循环等待、取出并执行cache queue中的request。把结果交给delivery。
- N个network dispatcher分别在独立的线程上运行。network dispatcher循环等待、取出并执行network queue中的request。把结果交给delivery和添加到cache中。
- delivery负责在主线程上将结果传给相应的listener回调。
“[Android] Volley库源码简析(HTTP Request部分)”的一个回复