学习内容:
1.NetWorkDispatcher网络请求线程调度...
2.NetWork网络请求抽象类...
3.BasicNetWork网络请求抽象类的具体实现...
4.NetWorkResponse接收网络请求返回的响应...
5.ResponseDelivery请求分配抽象类...
6.ExecutorDelivery请求分配的具体实现类...
上一章说完了缓存请求线程调度,那么现在就说一下网络请求线程调度是如何来完成的,网络请求线程调度也是有一个核心过程的,从网络上获取数据信息的过程, 首先从网络请求队列取出请求,如果请求存在,那么对请求进行相关的处理,如果没有请求,那么线程进入等待状态,取出请求之后需要先对请求是否已经被中途取 消进行相关的判断,如果已经请求已经被中途中断,那么结束这次的处理过程,如果没有取消,那么执行请求,获取服务器的返回数据,然后对返回的响应是够是 304响应进行相关的判断,如果是304响应,那么直接也结束对请求的处理。
304请求表示的是相同请求已经被服务器响应,并且返回了已经返回了相关的数据,由于服务器的状态是高并发的执行状态,有可能在同一时间段对两种或几种相同的请求进行相关的处理,那么对于这样多种相同的请求,服务器只需要响应一次数据就可以了,剩下的由ResponseDelivery去分发给所有与之相同的请求就可以了...也就是说服务器对于同一时间段的多个相同的请求只需要响应一次...
如果不是304响应,那么表示这次请求是一个新的请求,那么我们需要向服务器发送请求来获取服务器的响应,最后通过是否进行缓存进行判断之后,一个请求就可以被分发出去了...
1.NetWorkDispatcher.java
1.1 变量的定义
private final BlockingQueue<Request> mQueue; //请求队列...
/** The network interface for processing requests. */
private final Network mNetwork; //网络请求对象,用于执行网络请求工作
/** The cache to write to. */
private final Cache mCache; //缓存对象,用于缓存数据
/** For posting responses and errors. */
private final ResponseDelivery mDelivery; //用于分发请求...
/** Used for telling us to die. */
private volatile boolean mQuit = false; // 用于关闭线程...
1.2 NetWorkDispatcher构造函数...
网络请求线程调度对象的初始化过程...构造函数比较简单,没什么说的...
public NetworkDispatcher(BlockingQueue<Request> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}
1.3 public void run(){}
run()方法,线程中最重要的方法,必须要继承的...整个方式就如同刚开始介绍的一样,从请求队列中取出请求,然后判断请求是否被中断,中断就结束处理,没有中断就发送请求,然后对服务器是否已经对这次请求返回了响应数据,如果服务器已经响应了与之相同的请求,那么就停止对这次请求的处理,由分发响应函数去处理,如果是一个新的请求,那么需要定义一个请求对象,然后发送...最后获取到服务器响应后,对响应进行分发...
@Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程优先级... Request request; while (true) { try { // Take a request from the queue. 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; } // Tag the request (if API >= 14) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { //如果API>=10,那么为请求设置标签... TrafficStats.setThreadStatsTag(request.getTrafficStatsTag()); } // Perform the 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()) { //如果这个请求是没有改变..说白了就是请求如果是相同的...那么服务器就返回一次响应...其他的通过Delivery去分发就行了... request.finish("not-modified"); continue; } // Parse the response here on the worker thread. 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) { mCache.put(request.getCacheKey(), response.cacheEntry); //放入的操作... request.addMarker("network-cache-written"); } // Post the response back. 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)); } } } //一个错误处理函数,当发生解析请求或者是分发请求时出现错误时进行调用... private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) { error = request.parseNetworkError(error); mDelivery.postError(request, error); }
上面涉及到了执行请求...以及分发服务器响应,但是是如何实现的呢?我们先看如何去执行一个请求...
2.NetWork.java
NetWork.java是一个抽象的接口...对外提供一个执行请求方法的接口,方便其他类去实现...
package com.android.volley; /** * An interface for performing requests. */ public interface Network { /** * Performs the specified request. * @param request Request to process * @return A {@link NetworkResponse} with data and caching metadata; will never be null * @throws VolleyError on errors */ public NetworkResponse performRequest(Request<?> request) throws VolleyError; }
3.BasicNetWork.java
BasicNetWork是实现NetWork的具体抽象类,是如何执行请求的一个具体过程,其中内部也封装了一些其他方法...
3.1 变量的定义
这几个变量的定义相对比较抽象,但是会在下面细说...
protected static final boolean DEBUG = VolleyLog.DEBUG; //用于Volley内部调试.. private static int SLOW_REQUEST_THRESHOLD_MS = 3000;//对于缓慢的请求定义了一个请求时间... private static int DEFAULT_POOL_SIZE = 4096; //Int值,用于以后的获取网络数据... protected final HttpStack mHttpStack; //Http请求栈... protected final ByteArrayPool mPool; //ByteArrayPool对象...
3.2 public BasicNetWork(){}
构造函数...构造函数构造了一个保存Http请求栈,以及一个获取网络数据对象...
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 */ //建立一个BasicNetWork对象,这个对象保存了一个请求栈区,另一个参数用于获取数据而建立的对象... public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { mHttpStack = httpStack; mPool = pool; }
3.3 public NetworkResponse performRequest(Request<?> request) throws VolleyError {}
至关重要的方法,用于执行请求,这里我们也可以看到,请求传递的参数并没有写死,而是使用了泛型的方式形成了良好的扩展,也即是说传递过来的请求是什么类型,那么就执行什么类型的请求...
@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>(); //map集合,用于保存数据报的Header中的数据.. try { // Gather headers. Map<String, String> headers = new HashMap<String, String>(); //用于保存缓存下来的Header...缓存的Header一般包含服务响应的整体时间,缓存新鲜度验证等属性值... addCacheHeaders(headers, request.getCacheEntry()); //添加请求头部的过程... httpResponse = mHttpStack.performRequest(request, headers);//执行请求,获取响应.. StatusLine statusLine = httpResponse.getStatusLine();//获取响应状态... int statusCode = statusLine.getStatusCode();//获取状态码.. responseHeaders = convertHeaders(httpResponse.getAllHeaders());//获取响应后的Header中的所有数据... // Handle cache validation. //对304响应的一个判断过程,如果是304响应,那么直接走缓存,从缓存获取数据... if (statusCode == HttpStatus.SC_NOT_MODIFIED) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) {//判断响应是否是204判断,由于204响应时不返回数据信息的...因此需要判断... responseContents = entityToBytes(httpResponse.getEntity()); //如果存在内容,那么通过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 != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) { throw new IOException(); //如果请求状态出现错误,那么抛出异常... } return new NetworkResponse(statusCode, responseContents, responseHeaders, false); //如果请求不是304请求,并且上面异常情况也没有发生,那么返回新的请求中的内容+头部以及状态码... } 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);//url异常... } catch (IOException e) {//IO异常的处理... int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { //如果响应存在,但是出现异常.. statusCode = httpResponse.getStatusLine().getStatusCode(); //返回异常状态码..可以使客户端知道异常情况... } else { throw new NoConnectionError(e); } VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); if (responseContents != null) {//如果响应内容不是空... networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false);//获取响应... //请求需要进行验证,或者是需要授权异常处理... if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) { attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else { // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else { throw new NetworkError(networkResponse); } } } }
这个函数涉及了其他几个函数...
3.4 private void logSlowRequests(long requestLifetime, Request<?> request,byte[] responseContents, StatusLine statusLine) {}
记录一个请求——响应的时间超出了预先设置的缓慢请求时间,那么需要进行记录...记录响应码,响应内容等等函数比较的简单...
private void logSlowRequests(long requestLifetime, Request<?> request, byte[] responseContents, StatusLine statusLine) { if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " + "[rc=%d], [retryCount=%s]", request, requestLifetime, responseContents != null ? responseContents.length : "null", statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount()); }
3.5 private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {}
添加请求的请求头部,从缓存当中获取头部信息添加到这次请求...
private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) { // If there's no cache entry, we're done. if (entry == null) { //缓存数据为空...直接return return; } if (entry.etag != null) { headers.put("If-None-Match", entry.etag); //返回新鲜度验证标志.. } if (entry.serverDate > 0) { Date refTime = new Date(entry.serverDate); //返回请求——响应的时间... headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); } }
3.6 private static void attemptRetryOnException(String logPrefix, Request<?> request,VolleyError exception) throws VolleyError {}
尝试重试策略方法...如果请求发生了异常...
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)); }
3.7 private static Map<String, String> convertHeaders(Header[] headers) {}
上面涉及到了当响应返回的时候需要获取响应数据报的Header,将所有的Header数据获取并保存...以键值对的形式保存在map集合当中...最后传递给responseHeaders集合...
private static Map<String, String> convertHeaders(Header[] headers) { Map<String, String> result = new HashMap<String, String>(); for (int i = 0; i < headers.length; i++) { result.put(headers[i].getName(), headers[i].getValue()); } return result; }
3.8 private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {}
当Http请求响应成功时,我们需要从HttpEntity中获取返回的内容数据...数据的获取调用此函数..这个函数采用了PoolingArrayByteOutputStream()流..这个流采用了字节回收机制,可以减少内存的分配和回收...我们先知道就行...后面还会具体说明...
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); //新建一个流对象.. byte[] buffer = null; //缓冲字节.. try { InputStream in = entity.getContent();//将Entity中保存的内容封装成流... if (in == null) { throw new ServerError(); } buffer = mPool.getBuf(1024); //缓冲流分配...首先new一个缓冲字节数组... int count; while ((count = in.read(buffer)) != -1) { bytes.write(buffer, 0, count); //写入数据... } 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"); } mPool.returnBuf(buffer); bytes.close(); } }
这样总体就完成了请求之后响应数据的获取,也就是数据报的Header+Body的数据被保存了起来...那么完成了数据的获取,就需要响应数据的分发了...分发到请求才是请求——响应的一个最终完成过程...
4.NetWorkResponse.java
那么响应的传递就需要通过NetWorkResponse来进行传递,无论是从网络上获取的请求数据,还是从缓存当中获取的请求数据,都会被封装成NetWorkResponse,然后传递给相应请求中的parseNetWorkResponse方法,在进行下一步的处理...
package com.android.volley; import org.apache.http.HttpStatus; import java.util.Collections; import java.util.Map; /** * Data and headers returned from {@link Network#performRequest(Request)}. */ public class NetworkResponse { //对服务器的响应进行一个彻底封装... 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); } /** The HTTP status code. */ public final int statusCode; //响应状态码... /** Raw data from this response. */ public final byte[] data; //响应数据... /** Response headers. */ public final Map<String, String> headers; //以键值对的形式保存首部.. /** True if the server returned a 304 (Not Modified). */ public final boolean notModified; //304响应的判断... }
NetWorkResponse只是对服务器的响应的一个进一步封装,以参数的形式传递到Request.parseNetWorkResponse()方法...如果中间并么有出现什么异常情况,那么最后相应实现了Request.parseNetWorkResponse类会调用Response.success方法,将这次请求进行最后的封装,封装成Response<T>的形式,请求是什么类型,T就是什么类型...
5.Response.java
package com.android.volley; public class Response<T> { /** Callback interface for delivering parsed responses. */ public interface Listener<T> { /** Called when a response is received. */ public void onResponse(T response); //当一个请求——相应成功后的监听... } /** Callback interface for delivering error responses. */ 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); //当请求出现了错误时,需要监听错误.. } /** Returns a successful response containing the parsed result. */ public static <T> Response<T> success(T result, Cache.Entry cacheEntry) { return new Response<T>(result, cacheEntry); //success方法,当请求被解析成功时调用的方法... } /** * Returns a failed response containing the given error code and an optional * localized message displayed to the user. */ 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; //响应返回的结果.. /** Cache metadata for this response, or null in the case of error. */ public final Cache.Entry cacheEntry; //缓存... /** Detailed error information if <code>errorCode != OK</code>. */ public final VolleyError error; //一个错误对象...记录错误的生成... /** True if this response was a soft-expired one and a second one MAY be coming. */ public boolean intermediate = false; //判断一个请求是否失效... /** * 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; } }
当响应被封装成Response之后,就需要向客户端发送响应了,通过postResponse方法进行发送,如果一个响应成功,我们需要发送响应,但是如果中途出现了失败,那么我们需要把错误发送,需要让客户端清楚到底是发生了什么错误,这样在错误发生时提示用户到底应该怎样进行操作...
6.ResponseDelivery.java
解析响应之后的发送类,只是一个抽象的接口,我们可以人为去重写如何发送响应...而系统默认则采用线程池的方式对响应进行发送...
package com.android.volley; public interface ResponseDelivery { /** * Parses a response from the network or cache and delivers it. */ public void postResponse(Request<?> request, Response<?> response); //对响应进行发送... /** * Parses a response from the network or cache and delivers it. The provided * Runnable will be executed after delivery. */ public void postResponse(Request<?> request, Response<?> response, Runnable runnable); //对响应发送,同时开启一个线程去执行其他事情...线程在这个方法结束后执行... /** * Posts an error for the given request. */ public void postError(Request<?> request, VolleyError error); //发送错误信息... }
7.ExecutorDelivery.java
发送请求或者是错误的具体实现类,采用线程池的方式对响应进行发送...无论是服务器响应正确还是错误,我们都需要对其进行封装发送给客户端,让客户端去清楚服务器到底返回了什么东西...
package com.android.volley; import android.os.Handler; import java.util.concurrent.Executor; public class ExecutorDelivery implements ResponseDelivery { /** Used for posting responses, typically to the main thread. */ private final Executor mResponsePoster; //定义一个线程池... //定义了一个Response的传输接口... 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); } }; } //构造函数,定义了一个线程池... public ExecutorDelivery(Executor executor) { mResponsePoster = executor; } //发送请求的抽象方法的实现... @Override public void postResponse(Request<?> request, Response<?> response) { postResponse(request, response, null); } /*最后都是通过调用此方法来发送请求,因为poseResponse的方法有两种 * 一种是public void postResponse(Request<?> request, Response<?> response); * 另一种是 public void postResponse(Request<?> request, Response<?> response, Runnable 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..通过线程池的方式去管理这些线程...从这一步开始run()方法已经被调用了... } //如果出现了错误,那么将错误封装,同时也要发送给请求的客户端... @Override public void postError(Request<?> request, VolleyError error) { request.addMarker("post-error"); Response<?> response = Response.error(error); //封装错误.. mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null)); //发送错误... } @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; } //run方法... @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(); } } } }
我们可以看到,最后服务器的响应被封装之后,通过mRequest.deliveryResponse或者是mRequest.deliveryerror进行发送...而这两个方法就会在相应类型的请其中得到重写...因为所有的其他请求都是继承Request类的...Request类中只是一个抽象的方法,具体的实现在那些实际实现了Request的类中...而每一个实现类中都会去调用mListener.onResponse(response)方法,这里只表示请求成功时调用的方法...
abstract protected void deliverResponse(T response);
public interface Listener<T> { /** Called when a response is received. */ public void onResponse(T response); }
这样在客户端重写OnResponse方法之后,就彻底的完成了请求——响应的结束过程...数据也就成功的从服务器通过网络成功的发送给了客户端...