Volley源码解析
Posted this.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley源码解析相关的知识,希望对你有一定的参考价值。
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;
以上是关于Volley源码解析的主要内容,如果未能解决你的问题,请参考以下文章