尊重原创 http://write.blog.csdn.net/postedit/25921795

在前面的一片文章Volley框架浅析(一)中我们知道在RequestQueue这个类中,有两个队列:本地队列和网络队列

/** The cache triage queue. */
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<Request<? >>(); /** The queue of requests that are actually going out to the network. */
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<Request<? >>();

与之相应的分别有本地线程和网络线程。通过对RequestQueue源代码的分析,本地线程有一条。而网络线程默认有四条,我们能够对网络线程的个数进行设置,我们首先来学习一下本地线程:

(1) CacheDispatcher.java

public class CacheDispatcher extends Thread {

    private static final boolean DEBUG = VolleyLog.DEBUG;

	//本地队列,从RequestQueue中传递进来的
private final BlockingQueue<Request<?>> mCacheQueue; //网络请求队列。也是从RequestQueue中传递进来,当本地缓存没有命中时。须要把请求从本地队列增加网络队列
private final BlockingQueue<Request<?>> mNetworkQueue; //磁盘缓存对象
private final Cache mCache; //就是用于从子线程向Ui线程发送数据
private final ResponseDelivery mDelivery; /** Used for telling us to die. */
private volatile boolean mQuit = false; /**
* Creates a new cache triage dispatcher thread. You must call {@link #start()}
* in order to begin processing.
*
* @param cacheQueue Queue of incoming requests for triage
* @param networkQueue Queue to post requests that require network to
* @param cache Cache interface to use for resolution
* @param delivery Delivery interface to use for posting responses
*/
public CacheDispatcher(
BlockingQueue<Request<? >> cacheQueue, BlockingQueue<Request<? >> networkQueue,
Cache cache, ResponseDelivery delivery) {
mCacheQueue = cacheQueue;
mNetworkQueue = networkQueue;
mCache = cache;
mDelivery = delivery;
} /**
* Forces this dispatcher to quit immediately. If any requests are still in
* the queue, they are not guaranteed to be processed.
*/
public void quit() {
mQuit = true;
interrupt();
} @Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 缓存初始化,将磁盘中的数据读入内存
mCache.initialize(); while (true) {
try { // 堵塞式从队列中取出请求
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take"); // 推断request是否被取消了(调用cancel方法)。假设取消了就不运行,再次到队列中取请求
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()) {
// 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.
}
}
});
} } catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
}
}

(2) NetworkDispatcher.java

public class NetworkDispatcher extends Thread {
/** 网络队列 */
private final BlockingQueue<Request<? >> mQueue;
/** 用于Http请求,依据前面的学习,他事实上使用的是HttpURLConnection或者HttpClient. */
private final Network mNetwork;
/** 本地缓存,网络请求成功后。放入缓存. */
private final Cache mCache;
/** For posting responses and errors. */
private final ResponseDelivery mDelivery;
/** Used for telling us to die. */
private volatile boolean mQuit = false; /**
* Creates a new network dispatcher thread. You must call {@link #start()}
* in order to begin processing.
*
* @param queue Queue of incoming requests for triage
* @param network Network interface to use for performing requests
* @param cache Cache interface to use for writing responses to cache
* @param delivery Delivery interface to use for posting responses
*/
public NetworkDispatcher(BlockingQueue<Request<? >> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
} /**
* Forces this dispatcher to quit immediately. If any requests are still in
* the queue, they are not guaranteed to be processed.
*/
public void quit() {
mQuit = true;
interrupt();
} @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void addTrafficStatsTag(Request<?> request) {
// Tag the request (if API >= 14)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}
} @Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<? > request;
while (true) {
try {
// 从队列中堵塞式取出一个请求.
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 (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
} addTrafficStatsTag(request); // 通过NetWork的perfromRequest方法放回一个NetworkResponse对象
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete"); // 假设这个返回结果已经发送到了ui线程。就将它finish
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
} // 将NetworkResponse 解析成Response.
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();
//将数据发送到Ui线程
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
mDelivery.postError(request, new VolleyError(e));
}
}
} private void parseAndDeliverNetworkError(Request<? > request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}
}

通过上面的代码,我们来总结一下一个请求的运行过程吧:

1、一个请求就是一个Request对象,首先将Request对象增加到RequestQueue中.

2、推断Request能否够缓存,假设能够。则增加到本地缓存队列,否则增加网络队列

3、本地线程不断监听本地队列是否有请求。假设有请求取出来

4、推断Request是否取消,假设取消,处理下一个请求

5、推断缓存是否命中,假设没有命中。将该请求增加网络队列

6、假设命中,可是过期,相同将该请求增加网络队列

7、假设命中。而且不用刷新,那么直接放回结果。不用增加网络队列

8、假设命中,而且须要刷新。那么放回结果,而且增加网络队列

9、相同4条网络线程也在不断监听网络队列是否有请求,一旦发现有请求,取出请求,推断是否取消,假设取消。那么取出下一个请求

10、假设没有取消,那么通过NetWork进行http请求,将请求结果封装成NetworkResponse,然后转换为Response

11、假设能够缓存,那么将数据写入缓存

12、通过Delivery将Response返回到ui线程

通过以上12步,完毕了一个完整的请求



研究了这么久。我们还没有研究Request和Response是什么呢,假设熟悉http请求的同学相信非常好理解。

Request就是一个http请求。Response就是http返回的内容,先看看Request这个类吧

Request是一个抽象类。我仅仅介绍比較重要的几个方法:

public abstract class Request<T> implements Comparable<Request<T>> {
//Http 请求方法 POST,GET
private final int mMethod; /** 请求URL*/
private final String mUrl;
//用于出错时的回调接口
private final Response.ErrorListener mErrorListener; /** 这个请求在队列中的顺序 */
private Integer mSequence; ... /** 是否可以缓存 */
private boolean mShouldCache = true; /** 是否已经取消了,网络线程和本地线程都会对此推断,假设取消了就不请求了 */
private boolean mCanceled = false; /** 请求策略,比方设置最大重试次数之类的*/
private RetryPolicy mRetryPolicy; /**
* Creates a new request with the given method (one of the values from {@link Method}),
* URL, and error listener. Note that the normal response listener is not provided here as
* delivery of responses is provided by subclasses, who have a better idea of how to deliver
* an already-parsed response.
*/
public Request(int method, String url, Response.ErrorListener listener) {
mMethod = method;
mUrl = url;
mErrorListener = listener;
setRetryPolicy(new DefaultRetryPolicy()); mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
} /**
* Sets the retry policy for this request.
*
* @return This Request object to allow for chaining.
*/
public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
mRetryPolicy = retryPolicy;
return this;
} ... /**
* 通过此方法取消一个请求
*/
public void cancel() {
mCanceled = true;
} /**
* 推断是否已经取消.
*/
public boolean isCanceled() {
return mCanceled;
} /**
* 获取请求头
* @throws AuthFailureError In the event of auth failure
*/
public Map<String, String> getHeaders() throws AuthFailureError {
return Collections.emptyMap();
} /**
* Returns a Map of POST parameters to be used for this request, or null if
* a simple GET should be used. Can throw {@link AuthFailureError} as
* authentication may be required to provide these values.
*
* <p>Note that only one of getPostParams() and getPostBody() can return a non-null
* value.</p>
* @throws AuthFailureError In the event of auth failure
*
* @deprecated Use {@link #getParams()} instead.
*/
@Deprecated
protected Map<String, String> getPostParams() throws AuthFailureError {
return getParams();
} /**
* Returns a Map of parameters to be used for a POST or PUT request. Can throw
* {@link AuthFailureError} as authentication may be required to provide these values.
*
* <p>Note that you can directly override {@link #getBody()} for custom data.</p>
*
* @throws AuthFailureError in the event of auth failure
*/
protected Map<String, String> getParams() throws AuthFailureError {
return null;
} public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
} /**
* 设置是否能缓存
*
* @return This Request object to allow for chaining.
*/
public final Request<? > setShouldCache(boolean shouldCache) {
mShouldCache = shouldCache;
return this;
} /**
* 推断是否可以缓存
*/
public final boolean shouldCache() {
return mShouldCache;
} /**
* 这是个抽象方法,我们必须实现,用于将NetworkResponse 转化为Response
* @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); /**
* 这个我们也必须实现,用于将Response发送到ui线程
* @param response The parsed response returned by
* {@link #parseNetworkResponse(NetworkResponse)}
*/
abstract protected void deliverResponse(T response); } 以下继续看看Response这个类:
public class Response<T> { /** 成功的时候回调. */
public interface Listener<T> {
/** Called when a response is received. */
public void onResponse(T response);
} /** 失败的时候回调 */
public interface ErrorListener {
/**
* Callback method that an error has been occurred with the
* provided error code and optional user-readable message.
*/
public void onErrorResponse(VolleyError error);
} /** 成功的时候创建一个Response. */
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
return new Response<T>(result, cacheEntry);
} /**
* 失败的时候创建一个Response
*/
public static <T> Response<T> error(VolleyError error) {
return new Response<T>(error);
} /** Parsed response, or null in the case of error. */
public final T result; /**
* Returns whether this response is considered successful.
*/
public boolean isSuccess() {
return error == null;
} //私有的,我们无法调用
private Response(T result, Cache.Entry cacheEntry) {
this.result = result;
this.cacheEntry = cacheEntry;
this.error = null;
} private Response(VolleyError error) {
this.result = null;
this.cacheEntry = null;
this.error = error;
}
}

学习了上面两个类后,我们须要知道例如以下知识:

Volley中的不论什么请求都是继承Request的。如Volley提供的StringRequest,JsonArrayRequest,JsonObjectRequest

ImageRequest等等。而且要实现当中的两个方法

abstract protected Response<T> parseNetworkResponse(NetworkResponse response);



abstract protected void deliverResponse(T response);



T是泛型,StringRequest中T表示String,后期我将会简介这几种Request的使用,敬请大家期待。。





最后在介绍一个接口,就是ResponseDelivery.java

它的一个实现类是ExecutorDelivery.java

public class ExecutorDelivery implements ResponseDelivery {
/** 执行已提交的 Runnable 任务的对象。此接口提供一种将任务提交与每一个任务将怎样执行的机制(包含线程使用的细节、调度等)分离开来的方法。在线程池中经经常使用到 */
private final Executor mResponsePoster; /**
* 传入一个Handler,事实上就是执行在主线的Handler。我想你应该明确为什么他可以从子线程
将数据传入ui线程了
* @param handler {@link Handler} to post responses on
*/
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
//这里调用了handler的post方法
handler.post(command);
}
};
} /**
* Creates a new response delivery interface, mockable version
* for testing.
* @param executor For running delivery tasks
*/
public ExecutorDelivery(Executor executor) {
mResponsePoster = executor;
} @Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
} @Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
} /**
* A Runnable used for delivering network responses to a listener on the
* main thread.
*/
@SuppressWarnings("rawtypes")
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()) {
//在这里调用了deliverResponse
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();
}
}
}
}

好了,今天就写到这里吧,大家有什么不明确的欢迎留言讨论....

Android网络通信Volley框架源代码浅析(二)的更多相关文章

  1. Android网络通信Volley框架源代码浅析(一)

    尊重原创http://blog.csdn.net/yuanzeyao/article/details/25837897 从今天開始,我打算为大家呈现关于Volley框架的源代码分析的文章,Volley ...

  2. Android网络通信Volley框架源代码浅析(三)

    尊重原创 http://write.blog.csdn.net/postedit/26002961 通过前面浅析(一)和浅析(二)的分析.相信大家对于Volley有了初步的认识,可是假设想更深入的理解 ...

  3. Volley框架源代码分析

    Volley框架分析Github链接 Volley框架分析 Volley源代码解析 为了学习Volley的网络框架,我在AS中将Volley代码又一次撸了一遍,感觉这样的照抄代码也是一种挺好的学习方式 ...

  4. android图片缓存框架Android-Universal-Image-Loader(二)

    http://blog.csdn.net/king_is_everyone/article/details/35595515 这篇打算直接告诉大家怎么用吧,其实这个也不是很难的框架,大致使用过程如下: ...

  5. Android 网络通信框架Volley简介(Google IO 2013)

    1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient( ...

  6. Android 网络通信框架Volley(一)

    转自:http://blog.csdn.net/t12x3456/article/details/9221611 1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫 ...

  7. [转]Android 网络通信框架Volley简介(Google IO 2013)

    Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v= ...

  8. 【转】Android 网络通信框架Volley简介(Google IO 2013)

    Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v= ...

  9. Android 网络通信框架Volley简介

    1.1. Volley引入的背景在以前,我们可能面临如下很多麻烦的问题. 比如以前从网上下载图片的步骤可能是这样的流程: 在ListAdapter#getView()里开始图像的读取. 通过Async ...

随机推荐

  1. Two Seals codeforces 837c

    Two Seals 一个矩形a*b,若干子矩形,子矩形中选2个,不重叠能覆盖最大 思路: 枚举: 代码: #include <cstdio> #include <cstring> ...

  2. 制作Label标签文件时,使用convert_imageset.exe的注意事项

    当前的convert_imageset.exe版本做了一下修改 //status = ReadImageToDatum(root_folder + lines[line_id].first, //li ...

  3. linux下根目录扩容

    划分出一个磁盘,并将其格式化   [root@gg ~]# mkfs.ext3 /dev/sdb2    创建一个物理卷 [root@gg ~]# pvcreate /dev/sdb2    [roo ...

  4. C#基础语法补充

    [学习笔记]前接:https://www.cnblogs.com/aland-1415/p/7360509.html 一.异常处理 1.格式 try{ } catch{ } catch{ } ... ...

  5. LINUX 下挂载 exfat 格式 u 盘或移动硬盘

    apt-get update apt-get install exfat-utils

  6. Java异常处理中的恢复模型

    异常处理理论上有两种基本模型.Java支持终止模型,在这种模型中,假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行.一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行.长久以来,尽管 ...

  7. 美团外卖iOS多端复用的推动、支撑与思考

    背景 美团外卖2013年11月开始起步,随后高速发展,不断刷新多项行业记录.截止至2018年5月19日,日订单量峰值已超过2000万,是全球规模最大的外卖平台.业务的快速发展对技术支撑提出了更高的要求 ...

  8. MySQL 关于存储过程那点事

    存储例程是存储在数据库服务器中的一组sql语句,通过在查询中调用一个指定的名称来执行这些sql语句命令. 简介 SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完 ...

  9. shell rename directory

    mv can do two jobs. It can move files or directories It can rename files or directories To just rena ...

  10. Linux下使用thrfit

    1.安装boost.thrfit 2.生成gen-cpp 3.编译其中的server,方法为: (1).直接使用g++编译 g++ -o server HelloWorld.cpp helloworl ...