Volley分为三个线程,主线程、缓存调度线程、网络调度线程。当要执行request时,需要先将request加入到缓存调度队列,如果发现有相应的缓存结果,则将该结果解析然后回调到主线程;当没有发现相应的缓存调度结果时,发送Http请求,解析响应,写入缓存,回调响应结果到主线程
RequestQueue queue= Volley.newRequestQueue(getApplicationContext());
此处是作为Volley的入口,即获得一个请求队列,此队列是通过Volley类获得的。去看看Volley里做了什么
RequestQueue newRequestQueue(Context context)
RequestQueue newRequestQueue(Context context, HttpStack stack)
RequestQueue newRequestQueue(Context context, int maxDiskCacheBytes)
RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)
Volley共有四个构造函数,所有构造函数都会调用到第四个构造函数,即:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
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));
}
}
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();
return queue;
}
构造函数里,首先回去获得缓存文件目录,紧接着根据不同的版本创建不同的HttpStack,再创建了Network和RequestQueue,最后将请求队列queue返回。其中queue即是我们需要获得的请求队列,RequestQueue构造时接收两个参数,一个是DiskBasedCache缓存响应结果,另一个是Network执行网络请求。不禁要问,在Volley的构造过程中,具体做了些什么?
public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}
首先看的是HttpStack,HttpStack是一个接口,注释里写得很清楚,根据给予的参数执行Http请求
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
......
HttpURLConnection connection = openConnection(parsedUrl, request);
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);
// Initialize HttpResponse with data from the HttpURLConnection.
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
......
return response;
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
onPrepareRequest(httpRequest);
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
// TODO: Reevaluate this connection timeout based on more wide-scale
// data collection and possibly different for wifi vs. 3G.
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return mClient.execute(httpRequest);
}
上面分别是HurlStack和HttpClientStack对接口HttpStack的实现。 当版本大于等于9时选择的基于HttpConnection的HurlStack,反之为基于HttpClient的HttpClientStack。两种实现都对请求做了处理,包括请求头部的处理
接下来是Network
public interface Network {
/**
* Performs the specified request.
*/
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
Network也是一个接口,执行具体的请求
BasicNetwork(HttpStack httpStack)
BasicNetwork(HttpStack httpStack, ByteArrayPool pool)
NetworkResponse performRequest(Request<?> request)
BasicNetwork实现Network接口,且接收之前HttpStack ,并在performRequest里执行具体的请求
在以上的工作做好后,就可以创建RequestQueue
public class RequestQueue {
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
private final Map<String, Queue<Request<?>>> mWaitingRequests =
new HashMap<String, Queue<Request<?>>>()
PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<Request<?>>();
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<Request<?>>();
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private final Network mNetwork;
private final ResponseDelivery mDelivery;
private NetworkDispatcher[] mDispatchers;
private CacheDispatcher mCacheDispatcher;
}
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
}
public abstract class Request implements Comparable
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
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()里 , 会将所有的网络调度线程和缓存调度线程停止,见stop() . 然后分别开启新的网络调度线程和缓存调度线程。 那我们有必要看看两种调度线程是怎样运转的
首先是缓存调度进程
public CacheDispatcher(
BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
Cache cache, ResponseDelivery delivery) {
mCacheQueue = cacheQueue;
mNetworkQueue = networkQueue;
mCache = cache;
mDelivery = delivery;
}
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;
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;
}
// 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.
mNetworkQueue.put(request);
continue;
}
// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// 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");
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
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;
// 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());
}
}
}
CacheDispatcher继承Thread,构造函数接收缓存队列,网络队列,缓存,响应发送
run方法比较长,耐心看
首先,会将线程切换到后台进程,然后初始化Cache即DiskBasedCache,配置好缓存相关工作。接着不断轮询从缓存队列读取Request,读取到Request后, 如果Request被取消,finish这个Request,进入下一个轮询;从缓存中读取Request的响应结果,如果读取不到,将Request加入到网络队列,如果读取到但过期了,将Request加入网络队列,关联到缓存。response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders)) 这里执行网络请求并且得到Response。 别忘了, request是一个借口,所在稍后会看到它的具体实现。
public interface ResponseDelivery {
/**
* Parses a response from the network or cache and delivers it.
*/
public void postResponse(Request<?> request, Response<?> response);
/**
* Parses a response from the network or cache and delivers it. The provided
* Runnable will be executed after delivery.
*/
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
/**
* Posts an error for the given request.
*/
public void postError(Request<?> request, VolleyError error);
}
在得到请求响应Response后,用ResponseDelivery将Response回调给主线程,同样得,ResponseDelivery也是一个接口
再来是网络调度NetworkDispatcher
public NetworkDispatcher(BlockingQueue<Request<?>> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}
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 {
// Take a request from the queue.
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);
// 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.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// 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();
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);
}
}
}
NetworkDispatcher一样继承Thread,构造函数接收网络队列,网络具体执行Network, 缓存,响应发送。
run()里也将线程切换为后台线程,不断从网络队列里读取Request,如果Request被取消,停止请求,通过Network执行网络请求,获得NetworkResponse,利用NetworkResponse得到需要的Response。 得到请求响应后,根据Request(在建立Request时候可以设置,默认为true)是否需要缓存结果,决定是否把响应结果加入到缓存。最后用mDelivery将响应结果发送出去。
看完了start(),还需要看add(),了解Request是如何加入进RequestQueue的
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");
// 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持有RequestQueue的引用,然后将Request加入到当前请求。如果Request的响应结果不需要缓存,直接加入到网络队列,结束这次add() 。 Request响应结果需要缓存,从等待请求mWaitingRequests查看Request是否存在,存在说明Request正在执行请求但还没有结果,将Request加入mWaitingRequests,不重复请求;如果不存在,将Request加入mWaitingRequests,加入缓存队列作为重复求情的依据。
最后来看看一个Request的实例,借助StringRequest
public class StringRequest extends Request<String> {
private Listener<String> mListener;
/**
* Creates a new request with the given method.
*/
public StringRequest(int method, String url, Listener<String> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
/**
* Creates a new GET request.
*/
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
@Override
protected void onFinish() {
super.onFinish();
mListener = null;
}
@Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
@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));
}
}
parseNetworkResponse()将结果Parsed通过Response返回。 在之前的两个调度线程里,通过ResponseDelivery将结果发送出去,而ResponseDelivery是一个接口,在RequestQueue实例化的时候使用的是ExecutorDelivery,ExecutorDelivery实现了ResponseDelivery接口
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, 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.
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();
}
}
}
在ExecutorDelivery里postResponse()方法运行ResponseDeliveryRunnable,在这个Runnable里,如果Request已被取消,则不发送响应结果;如果响应结果成功调用mRequest.deliverResponse(mResponse.result),反之调用mRequest.deliverError(mResponse.error)。这里就会回调到StringRequest相应函数里,然后用StringRequest实例化时赋予的listener将结果回调到主线程。 到此,整个Volley流程结束
总结
1、在Volley实例RequestQueue, 将配置好的网路具体执行Network , 缓存DiskBasedCache 传给RequestQueue
2、RequestQueue 维护当前请求、等待请求、网络队列、缓存队列、缓存、请求响应传递、网络调度线程、缓存调度线程
3、在add新的Request时,根据不同的缓存需求对网络队列、缓存队列、等待请求做不同的操作。不缓存直接加入网络队列,缓存则加入缓存队列。 将缓存加入等待请求
4、缓存调度线程轮询时从缓存队列获取请求,再从缓存里获取此请求,命中则将请求响应结果发送出去,反之将请求加入到网络队列
5、网络调度线程轮询时从网络队列获取请求,获得请求响应结果后,如需缓存则缓存,然后将结果发送出去
6、调度线程通过具体的Request,调用parseNetworkResponse()方法获得response,然后通过ResponseDelivery接口将response发送出去,如在ExecutorDelivery里,ResponseDeliveryRunnable将结果回调到Request里,Request再回调用相应的listener将请求响应结果回调到主线程
此博客供个人笔记使用,如有错误之处,感谢指出