Volley最主要的功能其实就是跟网络打交道,然后从网络中获取相对应的数据,虽然有缓存线程(CacheDispatcher),但是如果缓存中没有对应的记录的话,还是会将其扔到网络队列中,由网络线程(NetworkDispatcher)来干活。
那么就看看NetworkDispatcher都干什么吧,如下:
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); // 调用mNetwork去跟网络打交道 NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过 if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // 分析响应的数据,返回Response对象 Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // 根据request的shouldCache字段来判断是不是需要缓存,如果需要,则将其放到mCache中。 if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // 调用 mDelivery将Response对象传回主线程进行UI的更新。 request.markDelivered(); mDelivery.postResponse(request, response); } catch (VolleyError volleyError) { parseAndDeliverNetworkError(request, volleyError);//有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示 } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); mDelivery.postError(request, new VolleyError(e)); } } }网络线程(NetworkDispatcher)主要做了几件事情:
1)调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。
2)判断请求有没有被取消,如果被取消,则重新获取请求。
3)调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。
4)调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。
5)判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。
6)调用 mDelivery将Response对象传到主线程中进行UI更新。
另外有一个要注意的就是,在Volley中,默认是有4个网络线程同时在跑的,而对应的缓存线程,则只有一个。
从上面的代码中,可以看到,网络线程其实是调用 Network对象去实现跟网络进行沟通的,而在Volley中,默认的Network实现类,则是BasicNetwork类。
下面我们就看看它的performRequest方法:
public NetworkResponse performRequest(Request<?> request) throws VolleyError { ... while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = new HashMap<String, String>(); try { // 添加头部信息 Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers);//调用HttpStack对象去网络中获取数据 StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // 从响应的状态行获取状态编码,如果是304(未修改),说明之前已经取过数据了,那么就直接利用缓存中的数据,构造一个NetworkResonse对象 if (statusCode == HttpStatus.SC_NOT_MODIFIED) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry() == null ? null : request.getCacheEntry().data, responseHeaders, true); } // 有些响应是不带内容的,比如响应状态编码是204的话,添加一个空的byte作为内容,后面好统一处理。 if (httpResponse.getEntity() != null) { responseContents = entityToBytes(httpResponse.getEntity()); } else { // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } ...//忽略了一些log的处理。 return new NetworkResponse(statusCode, responseContents, responseHeaders, false); } ...//这里忽略了一些异常处理 } catch (IOException e) { ... 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));//这里会根据Volley的Retyr机制进行重新获取。 } else { throw new ServerError(networkResponse); } } else { throw new NetworkError(networkResponse); } } } }
1)对于已经有缓存的请求,添加其头部信息,如下:
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.serverDate > 0) { Date refTime = new Date(entry.serverDate); headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); } }
3)根据状态编码来返回不同的Response对象,如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。
4)BasicNetwork实现了重试的机制,如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。
在Network中返回的NetworkResponse对象,会在NetworkDispatcher中由具体的Request(比如ImageRequest,JsonRequest)类来进行解析,再最后返回给UI线程。
结束!
关于缓存线程的介绍:
Android中关于Volley的使用(六)认识 CacheDispatcher