Volley是Android系统下的一个网络通信库,为Android提供简单快速的网络操作(Volley:Esay, Fast Networking for Android),下面是它的结构:
既然是网络通信库,自然会涉及到网络的基础操作:请求和响应,也是最基本的概念。客户端发出请求,服务端返回响应的字节数据,客户端解析得到想要的结果。Volley怎么设计这些基本的概念?
一、组件
1、Network
网络操作的定义,传入请求Request,得到响应NetworkResponse
public interface Network {
/**
* Performs the specified request.
* @param request Request to process
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
* @throws VolleyError on errors
*/
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
2、Request
请求的定义,包含网络请求的参数、地址等信息
public Request(int method, String url, Response.ErrorListener listener) {
mMethod = method;
mUrl = url;
mErrorListener = listener;
setRetryPolicy(new DefaultRetryPolicy());
mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
}
在Request中有两个抽象方法需要子类去实现,
/**
* Subclasses must implement this to parse the raw network response
* and return an appropriate response type. This method will be
* called from a worker thread. The response will not be delivered
* if you return null.
* @param response Response from the network
* @return The parsed response, or null in the case of an error
*/
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
/**
* Subclasses must implement this to perform delivery of the parsed
* response to their listeners. The given response is guaranteed to
* be non-null; responses that fail to parse are not delivered.
* @param response The parsed response returned by
* {@link #parseNetworkResponse(NetworkResponse)}
*/
abstract protected void deliverResponse(T response);
一个是 parseNetworkResponse,就是说对于返回的数据,需要怎么去解析,解析成什么类型的数据。一个具体的请求,应该知道自己想要什么结果,比如StringRequest就是将结果解析成String,而ImageRequest则是将结果解析成Bitmap,这里作为抽象方法留给具体的子类实现;
另一个是 deliverResponse,用于解析完成后将结果传递出去。这里传入的是解析好的数据类型,一般会在里面通过listener将结果传递到应用的场景下。如StringRequest,
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
3、NetworkResponse
网络请求通用返回结果,数据存储在data中
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
boolean notModified) {
this.statusCode = statusCode;
this.data = data;
this.headers = headers;
this.notModified = notModified;
}
4、Response<T>
响应结果的封装,包含最终结果result,缓存结构cacheEntry,出错信息error
private Response(T result, Cache.Entry cacheEntry) {
this.result = result;
this.cacheEntry = cacheEntry;
this.error = null;
}
二、执行过程
有了上面的基本数据结构,之后就是考虑怎么去操作这些结构,完成从请求到响应的整个过程。这里是整个Volley最核心的部分,也是体现作者设计思想的部分,涉及到任务调度、异步处理等。
1、RequestQueue
请求队列,所有请求都会通过RequestQueue的add方法加入到内部的队列里来等待处理,当请求结束得到响应结果后会调用finish方法将请求移出请求队列。
RequestQueue中包含以下成员:
- Cache 缓存结构,用于缓存响应结果;
- Network 网络操作的实现
- NetworkDispatcher 网络任务调度器
- CacheDispatcher 缓存任务调度器
- ResponseDelivery 响应投递,用于将结果从工作线程转移到UI线程
- cacheQueue 缓存任务队列
- networkQueue 网络任务队列
RequestQueue完成两项工作:
启动、停止调度器:
/**
* 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();
}
}
/**
* Stops the cache and network dispatchers.
*/
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
将请求添加到相应的队列中,之后各个调度器会自行取出处理
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;
}
}
从上面可以看出,一个请求不要求缓存的话会被直接加到networkQueue中,否则会加到cacheQueue中。那调度器是怎么自行取出来并进行处理呢?
2、CacheDispatcher,NetworkDispatcher
调度器是线程,队列阻塞,有请求就执行,没有就等待。对缓存调度器CacheDispatcher,如果在缓存中没有找到响应结果,就会将请求添加到网络调度器NetworkDispatcher中
while (true) {
try {
// Get a request from the cache triage queue, blocking until
// at least one is available.
final Request<?> request = mCacheQueue.take();
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.
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
NetworkDispatcher则是负责执行网络操作获取响应,调用Request解析响应从而得到指定的返回数据类型,将结果加入缓存,使用delivery将结果返回到UI线程。