本文主要是介绍[置顶] Android网络通信Volley框架源码浅析(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
[置顶] Android网络通信Volley框架源码浅析(二)
尊重原创 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框架源码浅析(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!