一、Volley框架图
Volley :Volley 对外暴露的 API,类中只有两个函数
通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue
。
Request<T> :表示一个请求的抽象类。
StringRequest
、JsonRequest
、ImageRequest
都是它的子类,表示某种类型的请求。
也可自定义自己的Request
RequestQueue :表示请求队列,一个RequestQueue对象包含:
一个CacheDispatcher
(用于处理走缓存请求的调度线程)、
一个
NetworkDispatcher
数组(默认数组大小为4,用于处理走网络请求的调度线程),
一个ResponseDelivery
(返回结果分发接口),
在start() 函数启动时会创建启动CacheDispatcher
和NetworkDispatchers
。
CacheDispatcher :Cache层中的一个线程,用于调度处理缓存的请求。
启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery
去执行后续处理。
当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher
去调度处理。
NetworkDispatcher:NetWork层中的一个线程,用于调度处理走网络的请求。
启动后会不断从网络请求队列中取请求处理,队列为空则等待,
请求处理结束则将结果传递给ResponseDelivery
去执行后续处理,并判断结果是否要进行缓存。
ResponseDelivery :返回结果分发接口,在创建RequestQueue对象时进行了初始化
在目前只有基于ExecutorDelivery
的在入参 handler 对应线程内进行分发。
HttpStack :处理 Http 请求,返回请求结果。在newRequestQueue中被初始化。
目前 Volley 中有基于 HttpURLConnection 的HurlStack
和 基于 Apache HttpClient 的HttpClientStack
。
上一篇中已经对其如何根据Android版本进行选择做了解析。
Network :调用HttpStack
处理请求,并将结果转换为可被ResponseDelivery
处理的NetworkResponse
。
在newRequestQueue中被初始化
Cache :缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCache
。
NetworkDispatcher
得到请求结果后判断是否需要存储在 Cache,CacheDispatcher
会从 Cache 中取缓存结果。
下面附上每个类之间的关系图:
RequestQueue mRequestQueue = Volley.newRequestQueue(this);看一下Volley.newRequestQueue的事务逻辑,Volley类中总共就两个方法:
/** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. */ public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); }代码的事务主体在这里:
/** Default on-disk cache directory. */ private static final String DEFAULT_CACHE_DIR = "volley"; /** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. */ public static RequestQueue newRequestQueue(Context context, HttpStack stack) { //创建cache File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } /** 根据博文http://blog.csdn.net/guolin_blog/article/details/12452307,HurlStack是用HttpURLConnection实现的; HttpClintStack是由HttpClient实现的;由Android2.3之前的版本宜使用HttpClient,因为其Bug较少; Android2.3之后版本宜使用HttpURLConnection,因其较轻量级且API简单; 故会有此HurlStack和HttpURLConnection的使用分类 */ if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } //创建以stack为参数的Network对象 Network network = new BasicNetwork(stack); //创建RequestQueue对象 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start();//继续向下分析的入口 return queue; }附I) 、HurlStack中的部分代码,可以看出其是基于HttpURLClient实现的:
private static HttpEntity entityFromConnection(HttpURLConnection connection)对应的HttpClientStack的构造函数可以看出其实基于HttpClient实现的:
public HttpClientStack(HttpClient client) { mClient = client; }而两者都是基于HttpStack接口的:
/** An HTTP stack abstraction.*/ public interface HttpStack { public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
由于Android 2.3版本之前,因为HttpURLConnection的BUG较多,HttpClient的API已经较完备,故宜使用HttpClient,故这里版本9之前,选择使用HttpClientStack;
Android2.3之后版本,HttpURLConnection不断发展,因其较为轻量级,且API使用较为简单,其也在不断优化性能等,故这里使用基于其的HurlStack;
/** * A network performing Volley requests over an {@link HttpStack}. */ public class BasicNetwork implements Network { ... private static int DEFAULT_POOL_SIZE = 4096; protected final HttpStack mHttpStack; protected final ByteArrayPool mPool; public BasicNetwork(HttpStack httpStack) { // If a pool isn't passed in, then build a small default pool that will give us a lot of // benefit and not use too much memory. this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); } /** * @param httpStack HTTP stack to be used * @param pool a buffer pool that improves GC performance in copy operations */ public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { mHttpStack = httpStack; mPool = pool; } ... }
/** Number of network request dispatcher threads to start. */ private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); } public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } /** * Creates the worker pool. Processing will not begin until {@link #start()} is called. * * @param cache A Cache to use for persisting responses to disk * @param network A Network interface for performing HTTP requests * @param threadPoolSize Number of network dispatcher threads to create * @param delivery A ResponseDelivery interface for posting responses and errors */ public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }在这里创建了之前分析中一个重要的对象:NetworkDispatcher;并且可以看到其类似线程池似的,创建了大小为threadPoolSize的NetworkDispatcher数组;其中的处理逻辑暂且不看,首先可以知道其是一个线程:
<span style="font-size:14px;"> public class NetworkDispatcher extends Thread</span>
/** * Starts the dispatchers in this queue. */ publicvoid 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(); } } /** Stops the cache and network dispatchers.*/ public void stop() { if (mCacheDispatcher != null) { mCacheDispatcher.quit(); } for (int i = 0; i < mDispatchers.length; i++) { if (mDispatchers[i] != null) { mDispatchers[i].quit(); } } }
/** * The set of all requests currently being processed by this RequestQueue. A Request * will be in this set if it is waiting in any queue or currently being processed by any dispatcher. */ private final Set<Request> mCurrentRequests = new HashSet<Request>(); /** * Adds a Request to the dispatch queue. * @param request The request to service * @return The passed-in request */ public Request add(Request request) { // Tag the request as belonging to this queue and add it to the set of current requests. request.setRequestQueue(this); //见附I Request设置其对应的RequestQueue synchronized (mCurrentRequests) { //mCurrentRequests表示当前该RequestQueue持有的requests,由HashSet来保存 mCurrentRequests.add(request); } // 为新添加的request进行一系列的初始化设置 request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); // 见附II 判断request是否允许缓存 if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } //request如果允许缓存 //Insert request into stage if there's already a request with the same cache key in flight. synchronized (mWaitingRequests) { // 见附III String cacheKey = request.getCacheKey(); if (mWaitingRequests.containsKey(cacheKey)) { // There is already a request in flight. Queue up. 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 { // Insert 'null' queue for this cacheKey, indicating there is now a request in // flight. mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); } return request; } }附:mCurrentRequests维护了一个正在进行中,尚未完成的请求集合。
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();附I)、Request.setRequestQueue() 字面上可以看出是Request设置其对应的RequestQueue,简单的setter函数:
/** The request queue this request is associated with. */ private RequestQueue mRequestQueue; /** * Associates this request with the given queue. The request queue will be notified when this * request has finished. */ public void setRequestQueue(RequestQueue requestQueue) { mRequestQueue = requestQueue; }
/** The queue of requests that are actually going out to the network. */ private final PriorityBlockingQueue<Request> mNetworkQueue = new PriorityBlockingQueue<Request>();
/** * Staging area for requests that already have a duplicate request in flight. * <ul> * <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache * key.</li> * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request * is <em>not</em> contained in that list. Is null if no requests are staged.</li> * </ul> */ private final Map<String, Queue<Request>> mWaitingRequests = new HashMap<String, Queue<Request>>();
1)对于每个新add的request,先获取它的CacheKey;
2)如果当前mWaitingRequests不存在当前cachekey,则会put(cacheKey, null);null表示当前Map中已经存在了一个对应cacheKey的请求;
3)如果mWaitingRequests已经存在了对应的cacheKey,通过get(Key)获取cacheKey对应的Queue;如果Queue为null,由第二步知,当前cacheKey仅仅对应一个request,则新建对应的Map Value值——Queue<Request>(这里由LinkedList来实现),然后添加进去即可;
mCacheQueue和
mNetworkQueue是想对应存在的:
mCacheQueue
放在缓存请求队列中的 Request,将通过缓存获取数据;
mNetworkQueue
放在网络请求队列中的 Request,将通过网络获取数据。
private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>(); private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();
****************************************************************** 下面是汇总,具体参看剩下两篇 **********************************************************
一、Volley工作流程图:
继续从CacheDispatcher和NetworkDispatcher开始看起。
二、CacheDispatcher:
一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery
去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher
去调度处理。
(一)看源码前,先看一下从其成员变量与处理流程:
BlockingQueue<Request<?>> mCacheQueue
缓存请求队列
BlockingQueue<Request<?>> mNetworkQueue
网络请求队列
Cache mCache
缓存类,代表了一个可以获取请求结果,存储请求结果的缓存
ResponseDelivery mDelivery
请求结果传递类
(3)源码:
1、构造函数:一系列赋值初始化操作
/** * Creates a new cache triage dispatcher thread. You must call {@link #start()} * in order to begin processing. */ public CacheDispatcher(BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue, Cache cache, ResponseDelivery delivery) { mCacheQueue = cacheQueue; mNetworkQueue = networkQueue; mCache = cache; mDelivery = delivery; }提到使用CacheDispatcher时一定要调用start()方法;而 CacheDispatcher的创建与线程start都是在RequestQueue中的add()函数中实现的:
// Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start();2、既然是线程,重点看其run()函数:
@Override public void run() { //设置优先级 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. //这里的Cache其实是DiskBasedCache,见附I mCache.initialize(); /*****循环处理逻辑******/ while (true) { try { // 从缓存队列 mCacheQueue中取出一个Request;如果mCacheQueue为空,则阻塞进行忙等待 final Request request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // 如果取出的Request请求已经被取消,则直接finish,处理下一个request if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // 尝试从缓存中获取request对应的结果 Cache.Entry entry = mCache.get(request.getCacheKey()); //为null,表示该cacheKey对应缓存结果不存在,则直接将request添加到mNetworkQueue中 if (entry == null) { request.addMarker("cache-miss"); mNetworkQueue.put(request); continue; } //如果缓存结果存在,但是已过期,同样也是将request添加到mNetworkQueue中 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // 如果命中(hit)找到了对应的缓存结果,则解析其数据为Response并返回给该request request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); // 还需判断缓存结果是否时间过久已经不新鲜,是否需要refresh if (!entry.refreshNeeded()) { // 不需要Refresh,则直接由mDelivery提交给相应的request mDelivery.postResponse(request, response); } else { // 如果已经不新鲜,mDelivery依旧提交结果给request, // 但同时要将Request传递给mNetworkQueue进行新鲜度验证 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) { } } }); } } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } } }附I)这里的Cache实际是DiskBasedCache,mCache.initialize()实际上调用的是 DiskBasedCache.initialize():
/** * Initializes the DiskBasedCache by scanning for all files currently in the * specified root directory. Creates the root directory if necessary. */ public synchronized void initialize()
三、NetworkDispatcher
一个线程,用于调度处理网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给 ResponseDelivery 去执行后续处理,并判断结果是否要进行缓存。
BlockingQueue<Request<?>> mQueue
网络请求队列
Network mNetwork
网络类,代表了一个可以执行请求的网络
Cache mCache
缓存类,代表了一个可以获取请求结果,存储请求结果的缓存
ResponseDelivery mDelivery
请求结果传递类,可以传递请求的结果或者错误到调用者
/** * Creates a new network dispatcher thread. You must call {@link #start()} * in order to begin processing. */ public NetworkDispatcher(BlockingQueue<Request> queue, Network network, Cache cache, ResponseDelivery delivery) { mQueue = queue; mNetwork = network; mCache = cache; mDelivery = delivery; }(4).其run()函数:
@Override public void run() { //设为后台进程 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request request; /*********循环处理逻辑********/ while (true) { try { // 从网络请求队列中取出request,同理mQueue为空时,也是忙等待 request = mQueue.take(); } catch (InterruptedException e) { if (mQuit) { return; } continue; } try { request.addMarker("network-queue-take"); // 如果取出的Request请求已经被取消,则直接finish,处理下一个request if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } // Tag the request (if API >= 14) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TrafficStats.setThreadStatsTag(request.getTrafficStatsTag()); } // 通过Network执行Request,获得NetworkResponse,故网络请求的处理逻辑应该都封装在了Network中 NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // 用来验证新鲜度,(notModified=304)响应为304且请求已经有了Response传输情况 if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // 将NetworkResponse解析为Response Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // 如果request可以被缓存,并且其请求实体补位空,则添加到mCache中 // TODO: Only update cache metadata instead of entire record for 304s. if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // 传输Response request.markDelivered(); 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)); } } }
一、Volley工作流程图:
NetworkResponse networkResponse = mNetwork.performRequest(request);看一下mNetwork的定义:(定义在NetworkDispatcher中)
/** The network interface for processing requests. */ private final Network mNetwork;NetworkDispatcher.mNetwork初始化发生在RequestQueue.start()中:
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);而RequestQueue.mNetwork是在其构造函数中传入的:
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }由前面分析知RequestQueue的构建是在Volley.newRequestQueue中实现的:
//创建以stack为参数的Network对象 Network network = new BasicNetwork(stack); //创建RequestQueue对象 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start();//继续向下分析的入口
HttpStack
处理请求,并将结果转换为可被ResponseDelivery
处理的NetworkResponse
。
@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = new HashMap<String, String>(); try { /** 忽略网络处理的细节*/ // Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); /**执行网络请求 * 这里调用了HttpStack.performRequest,并得到一个HttpResponse返回结果*/ httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); /**新鲜度验证: * 304 Not Modified:客户端有缓冲的文件并发出了一个条件性的请求 * (一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。 * 服务器告诉客户,原来缓冲的文档还可以继续使用。*/ if (statusCode == HttpStatus.SC_NOT_MODIFIED) { /** 解析成NetworkResponse,返回*/ return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } // 判断responses是否有实体信息,一些响应如204,并不包含content,所以需要验证 if (httpResponse.getEntity() != null) { //实体信息转化成byte[] responseContents = entityToBytes(httpResponse.getEntity()); } else { // 无实体信息情况 responseContents = new byte[0]; } // 超时情况处理. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine); if (statusCode < 200 || statusCode > 299) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false); } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException e) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { ... } } }
总结一下Network.performRequest所做的工作:
1、由传入的HttpStack对象执行网络请求:mHttpStack.performRequest()
2、解析响应结果,将HttpResponse解析成NetworkResponse;
3、对返回结果进行新鲜度验证(304)
4、将response的实体信息转化为byte数组
5、超时情况处理,如果发生超时,认证失败等错误,进行重试操作(attemptRetryOnException),直到成功、抛出异常(不满足重试策略等)结束。
attemptRetryOnException()是根据重试策略进行请求重试操作:
/** * Attempts to prepare the request for a retry. If there are no more attempts remaining in the * request's retry policy, a timeout exception is thrown. */ private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); try { retryPolicy.retry(exception); } catch (VolleyError e) { request.addMarker( String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); throw e; } request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); }
public interface HttpStack { /** * Performs an HTTP request with the given parameters. * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, * and the Content-Type header is set to request.getPostBodyContentType().</p> * @param request the request to perform * @param 发起请求之前,添加额外的请求 Headers {@link Request#getHeaders()} */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }2、HttpClientStack(使用HttpClient来实现)
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);//见附一 addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); onPrepareRequest(httpRequest);// Nothing.空函数,用于重写;该函数在request被excute之前被调用 //一些网络设置 HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest); }附一:createHttpRequest函数:
/** * 根据传进来的request来构造合适的HttpUriRequest */ static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: { // This is the deprecated way that needs to be handled for backwards compatibility. // If the request's post body is null, then the assumption is that the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getPostBody(); if (postBody != null) { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(request.getUrl()); } } /***********一般较多使用的是POST与GET,其等同于HttpClient的一般使用流程***************/ case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); //这里就看到了前面实现Request时,重写getBodyContentType()函数的意义 postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(request.getUrl()); putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(putRequest, request); return putRequest; } default: throw new IllegalStateException("Unknown request method."); } }3、HurlStack(由HttpURLConnection来实现)
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); //UrlRewriter见附一 if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { thrownew IOException("URL blocked by rewriter: " + url); } url = rewritten; } /**************HttpURLConnection的一般使用流程*******************/ URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); int responseCode = connection.getResponseCode(); if (responseCode == -1) { // -1 is returned by getResponseCode() if the response code could not be retrieved. // Signal to the caller that something was wrong with the connection. thrownew IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromConnection(connection)); for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } } return response; }附一:UrlRewriter
/** 对URLs在使用前进行重写转换*/ public interface UrlRewriter { /** * Returns a URL to use instead of the provided one, or null to indicate * this URL should not be used at all. */ public String rewriteUrl(String originalUrl); }参数 mUrlRewriter 通过HttpStack的构造函数传入进来,故可以自行进行定义:
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { mUrlRewriter = urlRewriter; mSslSocketFactory = sslSocketFactory; }
NetworkResponse networkResponse = mNetwork.performRequest(request);
int statusCode
Http 响应状态码
byte[] data
Body 数据
Map<String, String> headers
响应 Headers
boolean notModified
表示是否为 304 响应
long networkTimeMs
请求耗时
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, boolean notModified) { this.statusCode = statusCode; this.data = data; this.headers = headers; this.notModified = notModified; } public NetworkResponse(byte[] data) { this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false); } public NetworkResponse(byte[] data, Map<String, String> headers) { this(HttpStatus.SC_OK, data, headers, false); }3)回顾一下前面分析的设计NetworkResponse的类之间数据的传递关系:
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. mResponsePoster = new Executor() { @Override public void execute(Runnable command) { handler.post(command); } }; }可以看到很简单,就是使用主线程的Looper构建一个Handler,下面所有的post操作都是调用这个Handler来执行Runnable;
比如:
@Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); }将传递来的Response转化为ResponseDeliveryRunnable ,显然这是一个Runnable;
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()) { 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(); } } }在这个子线程中,转而调用 Request来deliverResponse:
以StringRequest为例,来看这个函数:
@Override protected void deliverResponse(String response) { if (mListener != null) { mListener.onResponse(response); } }这个Listener就是自己在定义Request的时候声明的ResponseListener,可以看到这个Listener工作在子线程中,所以如果要更新界面,注意使用Handler把消息传递主线程进行处理。
//创建ImageLoader imageLoader = new ImageLoader(httpUtils.getRequestQueue(), imageCache); public ImageLoader(RequestQueue queue, ImageCache imageCache) { mRequestQueue = queue; mCache = imageCache; }
// 获取最大内存缓存大小 int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); MAX_CACHE_SIZE = maxMemory / 8; // 定义为应用最大缓存的1/8 mImageLruCache = new LruCache<String, Bitmap>(MAX_CACHE_SIZE){ @Override protected int sizeOf(String url, Bitmap bitmap){ return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } }; // 创建ImageCache imageCache = new ImageLoader.ImageCache() { @Override public void putBitmap(String url, Bitmap bitmap) { mImageLruCache.put(url, bitmap); } @Override public Bitmap getBitmap(String url) { return mImageLruCache.get(url); } };使用LruCache来实现ImageCache接口,实现图片的内存缓存:
public interface ImageCache { public Bitmap getBitmap(String url); public void putBitmap(String url, Bitmap bitmap); }加载图片时的用法:
imageListener = ImageLoader.getImageListener(myImageView, default_pg, failed_pg); imageLoader.get(imageUrl, imageListener);来到ImageLoader#get:
public ImageContainer get(String requestUrl, final ImageListener listener) { return get(requestUrl, listener, 0, 0); } public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight) { return get(requestUrl, imageListener, maxWidth, maxHeight, ImageView.ScaleType.CENTER_INSIDE); } public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight, ImageView.ScaleType scaleType) { // 如果操作不是在主线程,则直接抛出异常 throwIfNotOnMainThread(); // 为图片的URL创建一个特定的cacheKey,注意这个cache还和图片的大小及scaleType相关 final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); // 这里会使用自定义的LruCache去获取一个Bitmap实例 Bitmap cachedBitmap = mCache.getBitmap(cacheKey); // 如果缓存中已经存在,则直接返回 if (cachedBitmap != null) { // Return the cached bitmap. ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); imageListener.onResponse(container, true); return container; } // 如果缓存中不存在,则进行获取 ImageContainer imageContainer = new ImageContainer(null, requestUrl, cacheKey, imageListener); // 通知Observer这时可以使用默认的图片 imageListener.onResponse(imageContainer, true); // 判断是否已经有了一个相同的请求在等待 BatchedImageRequest request = mInFlightRequests.get(cacheKey); if (request != null) { // If it is, add this request to the list of listeners. request.addContainer(imageContainer); return imageContainer; } // 创建一个Request,重复之前的流程 Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType, cacheKey); mRequestQueue.add(newRequest); mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; }处理逻辑大致和前面的addRequest相同,首先判断缓存中是否已经存在该url对应的bitmap,如果存在直接返回;如果不存在,先判断是否已经有了一个相同的请求在等待,如果是,把这个请求添加到监听者链表中;如果不存在,则创建一个Request<Bitmap>,添加到RequestQueue中,从网络中去获取;从网络中获取的流程和前面分析的相同。
先来看Request<Bitmap>:
protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight, ScaleType scaleType, final String cacheKey) { return new ImageRequest(requestUrl, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { onGetImageSuccess(cacheKey, response); } }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { onGetImageError(cacheKey, error); } }); }实际上返回一个ImageRequest类型,来看其请求成功的响应:即把获得的图片存储到缓存中;
protected void onGetImageSuccess(String cacheKey, Bitmap response) { // 把获取到的图片存储到缓存中 mCache.putBitmap(cacheKey, response); // 可以看到如果是多个相同请求在等待,则可以同时进行更新处理 BatchedImageRequest request = mInFlightRequests.remove(cacheKey); if (request != null) { // Update the response bitmap. request.mResponseBitmap = response; // Send the batched response batchResponse(cacheKey, request); } }最后NetWork执行的结果会封装成NetWorkResponse,通过ResponseDelivery进行转发,这个类最后会调用Request中deliverResponse方法:
@Override protected void deliverResponse(Bitmap response) { mListener.onResponse(response); }这个Listener就是最初定义的ImageListener:
public static ImageListener getImageListener(final ImageView view, final int defaultImageResId, final int errorImageResId) { return new ImageListener() { @Override public void onErrorResponse(VolleyError error) { if (errorImageResId != 0) { view.setImageResource(errorImageResId); } } @Override public void onResponse(ImageContainer response, boolean isImmediate) { if (response.getBitmap() != null) { view.setImageBitmap(response.getBitmap()); } else if (defaultImageResId != 0) { view.setImageResource(defaultImageResId); } } }; }
可以看到这里最终给View空间设置了图片,以上就是Volley实现图片加载的流程。