目源码的目录树:
- [android]
- ┗━[volley]
- ┣━AuthFailureError.java
- ┣━Cache.java
- ┣━CacheDispatcher.java
- ┣━DefaultRetryPolicy.java
- ┣━ExecutorDelivery.java
- ┣━InternalUtils.java
- ┣━Network.java
- ┣━NetworkDispatcher.java
- ┣━NetworkError.java
- ┣━NetworkResponse.java
- ┣━NoConnectionError.java
- ┣━ParseError.java
- ┣━RedirectError.java
- ┣━Request.java
- ┣━RequestQueue.java
- ┣━Response.java
- ┣━ResponseDelivery.java
- ┣━RetryPolicy.java
- ┣━ServerError.java
- ┣━TimeoutError.java
- ┣━[toolbox]
- ┃ ┣━AndroidAuthenticator.java
- ┃ ┣━Authenticator.java
- ┃ ┣━BasicNetwork.java
- ┃ ┣━ByteArrayPool.java
- ┃ ┣━ClearCacheRequest.java
- ┃ ┣━DiskBasedCache.java
- ┃ ┣━HttpClientStack.java
- ┃ ┣━HttpHeaderParser.java
- ┃ ┣━HttpStack.java
- ┃ ┣━HurlStack.java
- ┃ ┣━ImageLoader.java
- ┃ ┣━ImageRequest.java
- ┃ ┣━JsonArrayRequest.java
- ┃ ┣━JsonObjectRequest.java
- ┃ ┣━JsonRequest.java
- ┃ ┣━NetworkImageView.java
- ┃ ┣━NoCache.java
- ┃ ┣━PoolingByteArrayOutputStream.java
- ┃ ┣━RequestFuture.java
- ┃ ┣━StringRequest.java
- ┃ ┗━Volley.java
- ┣━VolleyError.java
- ┗━VolleyLog.java
可以看出,Volley源码放置得较为杂乱,不同功能模块的类并没有归到不同的包中。相比之下UIL的源码结构较为规范和合理。
从常用case入手,推断其项目架构
官网上给出的最简单的使用例子如下所示:
final TextView mTextView = (TextView) findViewById(R.id.text);
- // 1. 新建一个Queue
- RequestQueue queue = Volley.newRequestQueue(this);
- String url ="http://www.google.com";
- // 2. 新建一个Request,写好listener
- StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
- new Response.Listener<String>() {
- @Override
- public void onResponse(String response) {
- // Display the first 500 characters of the response string.
- mTextView.setText("Response is: "+ response.substring(0,500));
- }
- }, new Response.ErrorListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- mTextView.setText("That didn't work!");
- }
- });
- // 3. 将Request放到Queue里面执行
- queue.add(stringRequest);
- 结合下面这张图:
- 架构图
- 我们可以大致了解Volley的使用方法(见注释)和内部结构。下面就这个usecase展开进行源码级别的简述。
- Volley类
- Volley类提供了4个静态方法来方便用户新建Queue。其中:
- public static RequestQueue newRequestQueue(Context context) {
- return newRequestQueue(context, null);
- }
- 一句最终会调用:
- // 传入 context,stack=null,maxDiskCacheBytes=-1
- public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
- File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
- String userAgent = "volley/0"; //1. 设置userAgent
- try {
- String packageName = context.getPackageName();
- PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
- userAgent = packageName + "/" + info.versionCode;
- } catch (NameNotFoundException e) {
- }
- if (stack == null) {
- if (Build.VERSION.SDK_INT >= 9) { //2. 选择用哪个httpclient
- stack = new HurlStack();
- } else {
- // Prior to Gingerbread, HttpUrlConnection was unreliable.
- // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
- stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
- }
- }
- Network network = new BasicNetwork(stack);
- RequestQueue queue;
- if (maxDiskCacheBytes <= -1)
- {
- // No maximum size specified
- queue = new RequestQueue(new DiskBasedCache(cacheDir), network); //3. 新建Queue
- }
- else
- {
- // Disk cache size specified
- queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
- }
- queue.start();// 4. 传入Queue
- return queue;
- }
值得注意的是:
Volley会根据SDK的version来决定使用java.net.HttpURLConnection(Build.VERSION.SDK_INT >= 9)还是org.apache.http.client.HttpClient
新建Queue后,Queue马上会被start。
- stack类负责发送request(com.android.volley.Request)和获取response(org.apache.http.HttpResponse),network类负责分析和处理response,包装成NetworkResponse(com.android.volley.NetworkResponse)。
- 我们首先忽略掉network相关的细节,看一下queue的实现和request的调度策略。
- RequestQueue
- 先来看一下RequestQueue的构造方法:
- 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())));
- }
- 这里出现了一个新面孔ExecutorDelivery,根据字面意思可以猜测它是负责将请求的结果分发到主线程上,或者在主线程上执行回调(listener)。继续调用:
- public RequestQueue(Cache cache, Network network, int threadPoolSize,
- ResponseDelivery delivery) {
- mCache = cache;
- mNetwork = network;
- mDispatchers = new NetworkDispatcher[threadPoolSize];
- mDelivery = delivery;
- }
这里又出现了一个新面孔NetworkDispatcher。留意到threadPoolSize这个数组长度参数的字面意义,结合上面的Volley架构图,猜想NetworkDispatcher是一个work thread,循环等待并通过network执行在Queue上的request。
RequestQueue被实例化后,便调用其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();
- }
- }
- 相应地有:
- public void stop() {
- if (mCacheDispatcher != null) {
- mCacheDispatcher.quit();
- }
- for (int i = 0; i < mDispatchers.length; i++) {
- if (mDispatchers[i] != null) {
- mDispatchers[i].quit();
- }
- }
- }
这里的逻辑很简单:
开始之前停止所有旧的任务(即interrupt所有worker thread)。
启动一个负责cache的worker thread。
启动n个负责network的worker thread。
worker thread开始不断地等待来自Queue的request。
Request
接下来执行queue.add(stringRequest); ,一个request被加入到queue中,代码如下所示:
- public <T> Request<T> add(Request<T> request) {
- // Tag the request as belonging to this queue and add it to the set of current requests.
- request.setRequestQueue(this);
- synchronized (mCurrentRequests) {
- mCurrentRequests.add(request);
- }
- // Process requests in the order they are added.
- request.setSequence(getSequenceNumber());
- request.addMarker("add-to-queue"); // marker用来指示request当前的状态,实际上是用来打log
- // If the request is uncacheable, skip the cache queue and go straight to the network.
- if (!request.shouldCache()) {
- mNetworkQueue.add(request);
- return request;
- }
- // Insert request into stage if there's already a request with the same cache key in flight.
- synchronized (mWaitingRequests) {
- 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;
- }
- }
这里的逻辑是:
对新加进来的request进行一些设置。
如果不需要cache,那么把request直接加到network queue中。
根据key检查request是否正在执行。如果是,则将其放入到waiting链表中。猜想当request完成的时候会调用某个方法将key在waiting链表中删除,然后依次执行waiting的request。如果否,则将其加入cache queue中。
CacheDispatcher
假设该uri访问是***次执行,那么对应的request会被放到cache queue中。cache worker thread(cache dispatcher)发现cache queue中存在request,会马上将其dequeue并执行。我们来看一下CacheDispatcher的run方法:
- public class CacheDispatcher extends Thread {
- private final Cache mCache; // 一开始传入了“new DiskBasedCache(cacheDir)”
- ...
- public void quit() {
- mQuit = true;
- interrupt();
- }
- @Override
- public void run() {
- if (DEBUG) VolleyLog.v("start new dispatcher");
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // Make a blocking call to initialize the cache.
- mCache.initialize();
- Request<?> request;
- while (true) {
- // release previous request object to avoid leaking request object when mQueue is drained.
- request = null; //确保***一个request做完后能及时回收内存。
- try {
- // Take a request from the queue.
- request = mCacheQueue.take(); // 堵塞
- } catch (InterruptedException e) {
- // We may have been interrupted because it was time to quit.
- if (mQuit) {
- return; // 退出点
- }
- continue;
- }
- try {
- request.addMarker("cache-queue-take");
- // If the request has been canceled, don't bother dispatching it.
- if (request.isCanceled()) {
- request.finish("cache-discard-canceled");
- continue;
- }
- // miss cache则直接将request放到network queue中
- Cache.Entry entry = mCache.get(request.getCacheKey());
- if (entry == null) {
- request.addMarker("cache-miss");
- // Cache miss; send off to the network dispatcher.
- mNetworkQueue.put(request);
- continue;
- }
- // cache 过期了,直接将request放到network queue中
- if (entry.isExpired()) {
- request.addMarker("cache-hit-expired");
- request.setCacheEntry(entry);
- mNetworkQueue.put(request);
- continue;
- }
- // 将cache中的data包装成一个response
- request.addMarker("cache-hit");
- Response<?> response = request.parseNetworkResponse(
- new NetworkResponse(entry.data, entry.responseHeaders));
- request.addMarker("cache-hit-parsed");
- if (!entry.refreshNeeded()) {
- // cache不需要刷新,直接将response交给delivery
- mDelivery.postResponse(request, response);
- } else {
- // cache需要刷新。现将旧的内容返回,同时将request放进network queue。
- 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.
- final Request<?> finalRequest = request;
- mDelivery.postResponse(request, response, new Runnable() {
- @Override
- public void run() {
- try {
- mNetworkQueue.put(finalRequest);
- } catch (InterruptedException e) {
- // Not much we can do about this.
- }
- }
- });
- }
- } catch (Exception e) {
- VolleyLog.e(e, "Unhandled exception %s", e.toString());
- }
- }
- }
- }
接下来看一下mDelivery.postResponse这个方法。
ExecutorDelivery
从上文得知,mDelivery是一个ExecutorDelivery的实例(在新建RequestQueue时传入)。
ExecutorDelivery的初始化代码如下所示:
- public ExecutorDelivery(final Handler handler) {
- // Make an Executor that just wraps the handler.
- mResponsePoster = new Executor() { // java.util.concurrent.Executor;
- @Override
- public void execute(Runnable command) {
- handler.post(command);
- }
- };
- }
关于java.util.concurrent.Executor可以看这篇文章,这里就不展开了。
postResponse代码如下所示:
- @Override
- public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
- request.markDelivered(); //标记为已分发
- request.addMarker("post-response");
- mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); // 在初始化时传入的handler中执行ResponseDeliveryRunnable
- }
- ResponseDeliveryRunnable是ExecutorDelivery的一个子类,负责根据request的不同结果调用对应的listener方法:
- @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"); // 会调用 RequestQueue的finish方法
- return;
- }
- // Deliver a normal response or error, depending.
- if (mResponse.isSuccess()) {
- mRequest.deliverResponse(mResponse.result); //调用 listener的onResponse(response)
- } 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();
- }
- }
- }
接下来我们回头看看NetworkDispatcher对network queue的处理。
NetworkDispatcher
NetworkDispatcher的源码如下所示:
- public class NetworkDispatcher extends Thread {
- private final Network mNetwork; // BasicNetwork实例
- ...
- private final BlockingQueue<Request<?>> mQueue; // network queue
- ...
- public void quit() {
- mQuit = true;
- interrupt();
- }
- @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void addTrafficStatsTag(Request<?> request) { // 方便统计Volley的网络流量
- ...
- }
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Request<?> request;
- while (true) {
- long startTimeMs = SystemClock.elapsedRealtime();
- // release previous request object to avoid leaking request object when mQueue is drained.
- request = null;
- try {
- //1. 堵塞读取network queue中的request
- 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 the request was cancelled already, do not perform the
- // network request.
- if (request.isCanceled()) {
- request.finish("network-discard-cancelled");
- continue;
- }
- addTrafficStatsTag(request);
- //2. 在network对象中堵塞执行request
- NetworkResponse networkResponse = mNetwork.performRequest(request);
- request.addMarker("network-http-complete");
- // If the server returned 304 AND we delivered a response already,
- // we're done -- don't deliver a second identical response.
- if (networkResponse.notModified && request.hasHadResponseDelivered()) { // 304表示资源未被修改
- request.finish("not-modified");
- continue;
- }
- //3. 将NetworkResponse转成Response
- Response<?> response = request.parseNetworkResponse(networkResponse);
- request.addMarker("network-parse-complete");
- // Write to cache if applicable.
- // TODO: Only update cache metadata instead of entire record for 304s.
- if (request.shouldCache() && response.cacheEntry != null) {
- // 4. Response放到cache中
- mCache.put(request.getCacheKey(), response.cacheEntry);
- request.addMarker("network-cache-written");
- }
- //5. 通过Delivery回调结果
- 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);
- }
- }
- }
- private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
- error = request.parseNetworkError(error);
- mDelivery.postError(request, error);
- }
- }
NetworkDispatcher的处理流程和CacheDispatcher差不多,见注释。TrafficStats的介绍可以看这里。
上述代码的关键在于mNetwork.performRequest(request)和request.parseNetworkResponse(networkResponse)这两个调用。
- Network
- Network是一个接口,只有一个performRequest(Request<?> request)方法:
- public interface Network {
- public NetworkResponse performRequest(Request<?> request) throws VolleyError;
- }
本文例子中Network的实现类是BasicNetwork:
- public class BasicNetwork implements Network {
- protected static final boolean DEBUG = VolleyLog.DEBUG;
- private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
- 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));
- }
- ...
- }
- 注意到BasicNetwork的两个关键的成员:mHttpStack和mPool,和对apache依赖:
- import org.apache.http.Header;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.HttpStatus;
- import org.apache.http.StatusLine;
可我们先来看一下performRequest()的执行流程:
- public NetworkResponse performRequest(Request<?> request) throws VolleyError {
- long requestStart = SystemClock.elapsedRealtime();
- while (true) {
- // 依赖 org.apache.http.HttpResponse
- HttpResponse httpResponse = null;
- byte[] responseContents = null;
- Map<String, String> responseHeaders = Collections.emptyMap();
- try {
- // 1. 生成header
- Map<String, String> headers = new HashMap<String, String>();
- addCacheHeaders(headers, request.getCacheEntry());
- // 2. 通过httpstack发起请求。注意‘发起请求’这个动作不在request中进行,request只是保存着请求的信息。
- httpResponse = mHttpStack.performRequest(request, headers);
- // 3. 获得请求结果的一些信息
- StatusLine statusLine = httpResponse.getStatusLine();
- int statusCode = statusLine.getStatusCode();
- responseHeaders = convertHeaders(httpResponse.getAllHeaders());
- // 4. 通过statusCode(304)来判断是否可以直接使用cache
- if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
- Entry entry = request.getCacheEntry();
- if (entry == null) {
- return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
- responseHeaders, true,
- SystemClock.elapsedRealtime() - requestStart);
- }
- // 从cache中取出data,返回新的NetworkResponse
- entry.responseHeaders.putAll(responseHeaders);
- return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
- entry.responseHeaders, true,
- SystemClock.elapsedRealtime() - requestStart);
- }
- // 5. 通过statusCode通过判断是否需要重定向
- if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
- String newUrl = responseHeaders.get("Location");
- request.setRedirectUrl(newUrl);
- }
- // 6. 取出reponse中的data,为字节数组
- // Some responses such as 204s do not have content. We must check.
- if (httpResponse.getEntity() != null) {
- // 通过entityToBytes从outputstream中读取数据,throws IOException
- responseContents = entityToBytes(httpResponse.getEntity());
- } else {
- // Add 0 byte response as a way of honestly representing a
- // no-content request.
- responseContents = new byte[0];
- }
- // if the request is slow, log it.
- 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,
- SystemClock.elapsedRealtime() - requestStart);
- } 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) {
- // 7. 如果entityToBytes方法throw了IOException
- int statusCode = 0;
- NetworkResponse networkResponse = null;
- if (httpResponse != null) {
- statusCode = httpResponse.getStatusLine().getStatusCode();
- } else {
- throw new NoConnectionError(e);
- }
- if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
- statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
- VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
- } else {
- VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
- }
- // 如果reponseContent有数据
- if (responseContents != null) {
- networkResponse = new NetworkResponse(statusCode, responseContents,
- responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
- // 那么根据statusCode执行重试
- if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
- statusCode == HttpStatus.SC_FORBIDDEN) {
- attemptRetryOnException("auth",
- request, new AuthFailureError(networkResponse));
- } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
- statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
- attemptRetryOnException("redirect",
- request, new RedirectError(networkResponse));
- } else {
- // TODO: Only throw ServerError for 5xx status codes.
- throw new ServerError(networkResponse);
- }
- } else {
- throw new NetworkError(e);
- }
- }
- }
- }
attemptRetryOnException()代码如下所示:
- 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));
- }
RetryPolicy是一个接口:
- public interface RetryPolicy {
- public int getCurrentTimeout();
- public int getCurrentRetryCount();
- public void retry(VolleyError error) throws VolleyError;
- }
如没有特殊指定,request中的RetryPolicy为DefaultRetryPolicy,其retry方法实现如下:
- public void retry(VolleyError error) throws VolleyError {
- mCurrentRetryCount++;
- mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
- if (!hasAttemptRemaining()) {
- throw error;
- }
- }
如果还没超出重试次数上限,那么不会抛出异常,并返回到performRequest()的while循环中。接下来分析一下BaseNetwork的entityToBytes()方法:
- private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
- // 1. 新建PoolingByteArrayOutputStream
- PoolingByteArrayOutputStream bytes =
- new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
- byte[] buffer = null;
- try {
- InputStream in = entity.getContent();
- if (in == null) {
- throw new ServerError();
- }
- // 2. 在字节池中取出1024字节buffer
- buffer = mPool.getBuf(1024);
- int count;
- // 3. 从entity的inputStream中读出数据到buffer
- while ((count = in.read(buffer)) != -1) {
- // 将buffer写到PoolingByteArrayOutputStream中
- bytes.write(buffer, 0, count);
- }
- // 4. 将所有数据返回
- return bytes.toByteArray();
- } finally {
- try {
- // Close the InputStream and release the resources by "consuming the content".
- entity.consumeContent();
- } catch (IOException e) {
- // This can happen if there was an exception above that left the entity in
- // an invalid state.
- VolleyLog.v("Error occured when calling consumingContent");
- }
- // 5. 归还buffer到字节池
- mPool.returnBuf(buffer);
- bytes.close();
- }
- }
- 执行步骤见代码注释。这里不对ByteArrayPool类和PoolingByteArrayOutputStream展开。
- HttpStack
- HttpStack是一个接口,仅负责将request发送出去:
- public interface HttpStack {
- public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError;
- }
从最开始的对Volley类的分析可知,SDK version > 9的情况下使用HurlStack(java.net.HttpURLConnection),否则使用HttpClientStack(org.apache.http.client.HttpClient)。
stack各自实现了performRequest()方法,在内部正式发起了http请求。具体的用法参考各自的api文档,这里不详细展开了。
Request
Request类主要是保存着该次请求的参数和该次请求当前的状态,本身不含有请求相关的行为:
- public abstract class Request<T> implements Comparable<Request<T>> {
- ...
- public interface Method {
- int DEPRECATED_GET_OR_POST = -1;
- int GET = 0;
- int POST = 1;
- int PUT = 2;
- int DELETE = 3;
- int HEAD = 4;
- int OPTIONS = 5;
- int TRACE = 6;
- int PATCH = 7;
- }
- ...
- private final int mMethod;
- private final String mUrl;
- private String mRedirectUrl;
- private String mIdentifier;
- private final int mDefaultTrafficStatsTag;
- private Response.ErrorListener mErrorListener;
- private Integer mSequence;
- private RequestQueue mRequestQueue;
- private boolean mShouldCache = true;
- private boolean mCanceled = false;
- private boolean mResponseDelivered = false;
- private RetryPolicy mRetryPolicy;
- ...
- }
下面再来分析一下request.parseNetworkResponse(networkResponse)这个方法。以StringRequest为例:
- @Override
- protected Response<String> parseNetworkResponse(NetworkResponse response) {
- String parsed;
- try {
- parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
- } catch (UnsupportedEncodingException e) {
- parsed = new String(response.data);
- }
- return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
- }
- 可以看到它只是简单地将data转换成string,然后返回一个success的response。
- 而JsonObjectRequest的实现如下:
- @Override
- protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
- try {
- String jsonString = new String(response.data,
- HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
- return Response.success(new JSONObject(jsonString),
- HttpHeaderParser.parseCacheHeaders(response));
- } catch (UnsupportedEncodingException e) {
- return Response.error(new ParseError(e));
- } catch (JSONException je) {
- return Response.error(new ParseError(je));
- }
- }
它现将data转换成string,然后再生成一个JSONObject返回。
总结
综上,Volley的大致框架如下所述:
一个RequestQueue中包含两个内部queue,分别是cache queue和network queue。还有一个cache dispatcher和n个network dispatcher,它们都继承成于Thread,分别负责执行缓存和网络请求。还有一个delivery,负责分发请求结果。
cache dispatcher在独立的线程上运行。cache dispatcher循环等待、取出并执行cache queue中的request。把结果交给delivery。
N个network dispatcher分别在独立的线程上运行。network dispatcher循环等待、取出并执行network queue中的request。把结果交给delivery和添加到cache中。
delivery负责在主线程上将结果传给相应的listener回调。