Network是一个接口,它只包含一个方法,表示处理网络请求并返回处理结果:
1 public NetworkResponse performRequest(Request<?> request) throws VolleyError;
Network有一个唯一实现类BasicNetwork 。BasicNetwork使用HttpStack执行网络请求,成功后返回一个NetworkResponse,NetworkResponse只是一个简单的记录状态码,body,响应头,服务端是否返回304并且缓存过,执行网络请求时间的类。
首先看下他的构造方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /** * 带一个默认大小的ByteArrayPool缓冲池 * @param httpStack HTTP stack to be used */ 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(HttpStack*,ByteArrayPool*) * @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; }
有两个参数HttpStack和ByteArrayPool,这两个参数就是主要的成员变量。关于HttpStack和ByteArrayPool,建议阅读:HttpStack及其实现类源码解析 &&ByteArrayPool源码解析 。 BasicNetwork实现了NetWork接口的performRequest方法,我们来看下这个方法的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 /** * @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果 * @param Request * @return NetworkResponse * @throws VolleyError * 定义:{@link Network#performRequest(Request)} * 被调:{@link NetworkDispatcher#run()} * */ @Override//NetworkDispatcher的run()方法中调用 public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime();//开始请求时间 while (true) { HttpResponse httpResponse = null;//apache的请求结果 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());//先获取缓存数据 httpResponse = mHttpStack.performRequest(request, headers);//去调用mHttpStack的实现方法执行请求 StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线 int statusCode = statusLine.getStatusCode();//获取状态码 responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation.//处理缓存验证 if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据 return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } //把HttpEntity转化为byte[]数据 responseContents = entityToBytes(httpResponse.getEntity()); // if the request is slow, log it.//如果请求很慢,就打印出来看一下 long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印 //连接正常但是返回无内容,抛出IO异常 if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) { 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) {//Bad URL throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) {//IO异常 int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else {//如果没有返回httpResponse,就说明没连接 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);//只有状态码为5XX才抛出服务器异常 } } else {//网络异常 throw new NetworkError(networkResponse); } } } }
performRequest方法中,使用到了一个while循环,之所以使用while循环,是为了当出错的时候进行重试,关于重试策略,建议阅读:Volley的请求重试策略相关源码分析 。看下while循环中的代码: A. 获取和设置与条件请求相关的首部信息。
1 2 Map<String, String> headers = new HashMap<String, String>();//保存缓存数据 addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) { // If there's no cache entry, we're done. if (entry == null) { return; } if (entry.etag != null) { headers.put("If-None-Match", entry.etag); } if (entry.lastModified > 0) { Date refTime = new Date(entry.lastModified); headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); } }
从代码中可以看到,如果request.getCacheEntry()不为空,这时候会在设置请求首部的map中添加”If-None-Match”首部和”If-Modified-Since”首部,其值分别为缓存数据的etag和lastModified,”If-None-Match”和”If-Modified-Since”这两个首部是用来进行条件请求的,设置了这两个首部后,发起的请求就是条件请求。 注意在默认的情况下request.getCacheEntry()返回的是null,只有当请求存在缓存数据,但是缓存数据过期的情况下,request.getCacheEntry()才不会为空,具体的实现是在CacheDispatcher 的run方法中。在run方法中当获取到本地的缓存,但是本地缓存数据过期的时候,会将本地缓存的数据(首部信息和实体信息)放到Request中,然后将请求放入请求队列中,等待处理。
CacheDispatcher 的run方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Override public void run() { .... while (true) { try { .... 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; } if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } .... } }
B. 调用传入的HttpStack的performRequest方法去执行请求,并将响应结果封装成一个HttpResponse。
1 httpResponse = mHttpStack.performRequest(request,headers);//去调用mHttpStack的实现方法执行请求
C. 获取响应结果的状态码和响应的首部信息,然后根据响应结果的状态码,进行相关的操作。 如果状态码是304,则直接使用本地的缓存数据和响应的首部信息,构造NetworkResponse并返回。
1 2 3 4 5 6 7 8 StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线 int statusCode = statusLine.getStatusCode();//获取状态码 responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation.//处理缓存验证 if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据 return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,request.getCacheEntry().data,responseHeaders, true); }
1 2 3 4 5 6 7 protected static Map<String, String> convertHeaders(Header[] headers) { Map<String, String> result = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER); for (int i = 0; i < headers.length; i++) { result.put(headers[i].getName(), headers[i].getValue()); } return result; }
如果状态码不是304,说明可能有数据返回,获取响应实体,然后解析响应实体的内容,获得byte[]数组,利用获取到的byte[]数组和响应的首部信息,构造NetworkResponse并返回。
1 responseContents = entityToBytes(httpResponse.getEntity());
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); byte[] buffer = null; try { InputStream in = entity.getContent(); if (in == null) { throw new ServerError(); } buffer = mPool.getBuf(1024); 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(); } }
这里用到了PoolingByteArrayOutputStream,关于PoolingByteArrayOutputStream,建议阅读:PoolingByteArrayOutputStream源码解析 。 D. 当出现异常的时候,进行相关的操作,这里主要关心Volley的重试策略,建议阅读:Volley的请求重试策略相关源码分析 。
参考链接:
谷歌Volley网络框架讲解——Network及其实现类
Http status code : 304 HTTP状态码
上一篇:Volley-DiskBasedCache的内部类CacheHeader的源码分析
下一篇:Volley的请求重试策略相关源码分析