Android Volley 源码解析(一),android应用程序开发的流程

public void start() {

stop();

mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);

mCacheDispatcher.start();

for (int i = 0; i < mDispatchers.length; i++) {

NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,

mCache, mDelivery);

mDispatchers[i] = networkDispatcher;

networkDispatcher.star
t();

}

}

public void stop() {

if (mCacheDispatcher != null) {

mCacheDispatcher.quit();

}

for (final NetworkDispatcher mDispatcher : mDispatchers) {

if (mDispatcher != null) {

mDispatcher.quit();

}

}

}

先调用 stop() 方法将当前正在进行 Dispatcher 都停掉,然后创建了一个 CacheDispatcher 实例,并调用了它的 start() 方法,接着在一个循环里去创建 NetworkDispatcher 的实例,分别调用它们的 start() 方法,这里的 CacheDispatcher 和 NetworkDispatcher 都是继承自 Thread 的,默认情况下 for 循环会执行四次,也就是说当调用了 Volley.newRequestQueue(context) 之后,就会有五个线程在后台运行,等待网络请求的到来,其中 CacheDispatcher 是缓存线程,NetworkDispatcher 是网络请求线程。

得到 RequestQueue 之后,构建相应的 Request,然后调用 add() 方法将其加入到请求队列中

public Request add(Request request) {

// 将 Request 标记为属于此队列,并将其放入 mCurrentRequests 中

request.setRequestQueue(this);

synchronized (mCurrentRequests) {

mCurrentRequests.add(request);

}

// 让 Request 按照他们被添加的顺序执行

request.setSequence(getSequenceNumber());

request.addMarker(“add-to-queue”);

//如果请求不需要被缓存,就跳过缓存,直接进行网络请求

if (!request.shouldCache()) {

mNetworkQueue.add(request);

return request;

}

mCacheQueue.add(request);

return request;

}

可以看到,传入 Request 之后,会先判断该 Request 是否需要进行缓存,如果不需要就直接将其加入到网络请求队列,需要缓存则加入缓存队列。默认情况下,每条请求都是应该缓存的,当然我们也可以调用 Request 的 setShouldCache() 方法来进行设置。

Request 被添加到缓存队列中后,在后台等待的缓存线程就要开始运行起来了,我们看下 CacheDispatcher 的 run() 方法究竟是怎么实现的。

@Override

public void run() {

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

// 初始化 Cache

mCache.initialize();

while (true) {

try {

processRequest();

} catch (InterruptedException e) {

if (mQuit) {

return;

}

}

}

}

private void processRequest() throws InterruptedException {

final Request<?> request = mCacheQueue.take();

request.addMarker(“cache-queue-take”);

// 如果请求已经取消了,我们直接结束该请求

if (request.isCanceled()) {

request.finish(“cache-discard-canceled”);

return;

}

// 从 Cache 中取出包含请求缓存数据的 Entry

Cache.Entry entry = mCache.get(request.getCacheKey());

if (entry == null) {

request.addMarker(“cache-miss”);

if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {

mNetworkQueue.put(request);

}

return;

}

// 如果缓存的请求过期了,就将其添加到网络请求队列中

if (entry.isExpired()) {

request.addMarker(“cache-hit-expired”);

request.setCacheEntry(entry);

if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {

mNetworkQueue.put(request);

}

return;

}

// 缓存的数据封装成 NetworkResponse

Response<?> response = request.parseNetworkResponse(

new NetworkResponse(entry.data, entry.responseHeaders));

if (!entry.refreshNeeded()) {

// 如果缓存没有过期就直接进行分发

mDelivery.postResponse(request, response);

} else {

// 重置该请求的 Entry

request.setCacheEntry(entry);

response.intermediate = true;

if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {

mDelivery.postResponse(request, response, new Runnable() {

@Override

public void run() {

try {

mNetworkQueue.put(request);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

});

} else {

mDelivery.postResponse(request, response);

}

}

}

代码相对比较长,我在关键的地方已经打上注释了,在这里总结一下,可以看到在初始化了 Cache 之后,有一个 while(true) 循环,说明缓存线程是始终执行的,接着会在缓存中取出响应结果,如果为 null 的话,就将其加入到网络请求队列中,如果不为空的话,再判断该缓存是否已过期,已经过期则同样把这条请求加入到网络请求队列中,否则直接使用缓存中的数据。最后将数据进行解析,并进行分发。

看完 CacheDispathcer 的 run() 方法,我们接着看 NetworkDispatcher 的 run() 方法

@Override

public void run() {

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

while (true) {

try {

processRequest();

} catch (InterruptedException e) {

if (mQuit) {

return;

}

}

}

}

private void processRequest() throws InterruptedException {

Request<?> request = mQueue.take();

long startTimeMs = SystemClock.elapsedRealtime();

try {

request.addMarker(“network-queue-take”);

// 如果 Request 已经取消了,那就不执行网络请求

if (request.isCanceled()) {

request.finish(“network-discard-cancelled”);

request.notifyListenerResponseNotUsable();

return;

}

addTrafficStatsTag(request);

// 执行网络请求

NetworkResponse networkResponse = mNetwork.performRequest(request);

// 如果服务器返回 304,而且我们已经分发过该 Request 的结果,那就不用进行第二次分发了

//(这里补充一下,304 代表服务器上的结果跟上次访问的结果是一样的,也就是说数据没有变化)

if (networkResponse.notModified && request.hasHadResponseDelivered()) {

request.finish(“not-modified”);

request.notifyListenerResponseNotUsable();

return;

}

// 在子线程解析返回的结果

Response<?> response = request.parseNetworkResponse(networkResponse);

// 如果需要的话,就将返回结果写入缓存

if (request.shouldCache() && response.cacheEntry != null) {

mCache.put(request.getCacheKey(), response.cacheEntry); }

// 分发响应结果

request.markDelivered();

mDelivery.postResponse(request, response);

request.notifyListenerResponseReceived(response);

} catch (VolleyError volleyError) {

request.notifyListenerResponseNotUsable();

} catch (Exception e) {

request.notifyListenerResponseNotUsable();

}

}

在 NetworkDispatcher 同样使用了 while(true),说明网络请求线程也是不断运行的。然后从网络队列里面取出 Request,再调用 Network 的 performRequest() 方法去发送网络请求。Network 其实是一个接口,这里具体的实现是 BasicNetwork,我们来看下它的 performRequest() 方法实现:

@Override

public NetworkResponse performRequest(Request<?> request) throws VolleyError {

long requestStart = SystemClock.elapsedRealtime();

while (true) {

HttpResponse httpResponse = null;

byte[] responseContents = null;

List

responseHeaders = Collections.emptyList();

try {

Map<String, String> additionalRequestHeaders =

getCacheHeaders(request.getCacheEntry());

// 该注意的地方:调用 Stack 的 executeRequest 进行网络请求

httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);

int statusCode = httpResponse.getStatusCode();

responseHeaders = httpResponse.getHeaders();

if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {

Entry entry = request.getCacheEntry();

if (entry == null) {

return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, true,

SystemClock.elapsedRealtime() - requestStart, responseHeaders);

}

List

combinedHeaders = combineHeaders(responseHeaders, entry);

return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data,

true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders);

}

// 有些返回结果是没有内容的,如:204,所以我们必须进行检查

InputStream inputStream = httpResponse.getContent();

if (inputStream != null) {

responseContents =

inputStreamToBytes(inputStream, httpResponse.getContentLength());

} else {

responseContents = new byte[0];

}

return new NetworkResponse(statusCode, responseContents, false,

SystemClock.elapsedRealtime() - requestStart, responseHeaders);

} catch (Exception e) {

// …

}

}

}

这个方法里面,基本上都是网络请求方面处理的细节,我们这篇文章,主要是梳理整体的流程,对细节方面先不深入。需要注意的是在我标注的第一个地方,调用了 Stack 的 executeRequest() 方法,这里的 Stack 就是之前调用 Volley.newRequestQueue() 所创建的实例,前面也说过了这个对象的内部是使用了 HttpURLConnection 或 HttpClient(已弃用)来进行网络请求。网络请求结束后将返回的数据封装成一个 NetworkResponse 对象进行返回。

在 NetworkDispatcher 接收到了这个 NetworkResponse 对象之后,又会调用 Request 的 parseNetworkResponse() 方法来对结果进行解析,然后将数据写入到缓存,最后调用 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));

ction 或 HttpClient(已弃用)来进行网络请求。网络请求结束后将返回的数据封装成一个 NetworkResponse 对象进行返回。

在 NetworkDispatcher 接收到了这个 NetworkResponse 对象之后,又会调用 Request 的 parseNetworkResponse() 方法来对结果进行解析,然后将数据写入到缓存,最后调用 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));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值