Volley是Google开发的一个网络请求框架,该框架适合进行小而频繁的网络请求。
Volley的使用比较简单,只需几个简单的操作就可以实现发送请求。以StringRequest 为例:
//创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(this);
String url = "request_url";
//创建StringRequest对象,以Post数据为例
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.i("TAG", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.i("TAG", error.toString());
}
}) {
//填写需要post的表单
@Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> map = new HashMap<>();
map.put("userId", "0"); //测试数据
map.put("sessionId", "0");
return map;
}
};
requestQueue.add(request);
首先需要看看 Volley.newRequestQueue(this) 这句是如何实现的:
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
//缓存路径
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
//代码省略
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
//实现请求的类
Network network = new BasicNetwork(stack);
//创建一个请求队列
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
这里需要关注的是当SDK版本小于9时,就会使用HttpClientStack来完成请求,否则,则用HurlStack。前者使用的是HttpClient,而后者使用的是HttpURLConnection。
接着,执行了queue.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();
}
}
上述代码中出现了两个分发器:CacheDispatcher和NetworkDispatcher。它们都是继承Thread,分别用于处理缓存和网络请求。其中处理网络请求的线程有4个。
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
既然是线程的子类,并且都调用了start方法启动线程,那么就需要看看run方法是如何实现的:
CacheDispatcher
@Override
public void run() {
//代码省略
while (true) {
try {
//不断地从队列中读取请求
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
// 如果请求被取消了,就不再处理
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// 取出网络请求的缓存
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// 如果找不到,就交由网络请求线程去处理
mNetworkQueue.put(request);
continue;
}
// 缓存过期,交由网络请求线程去处理
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// 命中缓存,写入数据
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
mDelivery.postResponse(request, response);
} else {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
response.intermediate = true;
//发送请求结果
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
}
}
});
}
} catch (InterruptedException e) {
// 超时
if (mQuit) {
return;
}
continue;
}
}
}
NetworkDispatcher
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// 取出请求
request = mQueue.take();
} catch (InterruptedException e) {
// 超时
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// 如果取消,不做处理
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
addTrafficStatsTag(request);
// 执行网络请求,mNetwork就是之前创建队列时的BasicNetwork,里面具体实现了网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// 解析返回结果
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");
}
// 回调结果
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);
}
}
}
接着需要看看请求结果是如何被回调的:
mDelivery.postResponse(request, response),其实是调用了ExecutorDelivery中的postResponse方法:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
//线程池添加任务
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
再看看该任务中的run方法:
@Override
public void run() {
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
if (mResponse.isSuccess()) {
//此处会调用Request的onResponse方法,实现回调
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
if (mRunnable != null) {
mRunnable.run();
}
}
至此,对于网络请求是如何处理的有了一定的了解。紧接着看看每次添加网络请求是如何实现的,即add方法:
public <T> Request<T> add(Request<T> request) {
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
//把请求添加到集合
mCurrentRequests.add(request);
}
// 添加顺序
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// 如果设置不缓存,直接走网络
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// 否则,添加到缓存中,该缓存的键值对为cacheKey和request
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
//查找是否有相同键,取出对应请求
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 {
//没有对应request就设置为null
mWaitingRequests.put(cacheKey, null);
//添加到处理缓存队列
mCacheQueue.add(request);
}
return request;
}
}