[关闭]
@946898963 2018-05-18T04:17:59.000000Z 字数 3738 阅读 919

Volley-NetworkDispatcher源码解析

Android控件跟框架 Android源码分析


在RequestQueue中存在两个队列,一个是缓存请求队列,另一个是网络请求队列,缓存请求队列中存放的是允许使用本地缓存的请求,网络请求队列中存放的是不允许使用缓存或者是本地不存在缓存的请求。在RequestQueue.add方法中,如果使用缓存,就直接将Request放入缓存队列mCacheQueue中了,如果不允许缓存,就直接将请求放入网络请求队列。

在RequestQueue中存在一个缓存线程,缓存线程从缓存请求队列中,取出请求,查找本地缓存,如果查找不到本地缓存,就将这个请求放入网络请求队列中去,如果查找到混存,就直接分发缓存结果。同时在RequestQueue中存在四条请求线程,负责从网絡请求队列中取出请求,从网络中获取数据。CacheDispatcher就是前面提到的缓存线程,而网络请求线程是NetworkDispatcher

此处输入图片的描述

接下来对NetworkDispatcher的源码进行分析。

成员变量:

  1. /** 请求队列,是一个阻塞队列 */
  2. private final BlockingQueue<Request<?>> mQueue;
  3. /** 网络请求的具体实现类 */
  4. private final Network mNetwork;
  5. /** Volley缓存的操作类 */
  6. private final Cache mCache;
  7. /** Volley的响应分发类 */
  8. private final ResponseDelivery mDelivery;
  9. /** 请求线程的中断标志位 */
  10. private volatile boolean mQuit = false;
  • mQueue,请求队列,是一个阻塞队列,用于保存网络请求
  • mNetwork,网络请求接口,具体实现类BasicNetwork,用于进行网络请求
  • mCache,缓存接口,具体实现类DiskBasedCache,用于进行数据缓存
  • ResponseDelivery,响应分发接口,具体实现类:ExecutorDelivery,用于分发响应
  • mQuit,请求线程的中断标志位

构造方法:

  1. public NetworkDispatcher(BlockingQueue<Request<?>> queue,
  2. Network network, Cache cache,
  3. ResponseDelivery delivery) {
  4. mQueue = queue;
  5. mNetwork = network;
  6. mCache = cache;
  7. mDelivery = delivery;
  8. }

就是对成员变量赋值。

run方法(主要方法):

  1. @Override
  2. public void run() {
  3. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  4. while (true) {
  5. long startTimeMs = SystemClock.elapsedRealtime();
  6. Request<?> request;
  7. try {
  8. // 从队列中获取一个请求,如果没有请求,则会一直阻塞
  9. request = mQueue.take();
  10. } catch (InterruptedException e) {
  11. // We may have been interrupted because it was time to quit.
  12. if (mQuit) {
  13. return;
  14. }
  15. continue;
  16. }
  17. try {
  18. request.addMarker("network-queue-take");
  19. //判断请求有没有取消,如果取消,则不必再继续
  20. if (request.isCanceled()) {
  21. request.finish("network-discard-cancelled");
  22. continue;
  23. }
  24. //流量统计用的
  25. addTrafficStatsTag(request);
  26. // 调用mNetwork请求数据
  27. NetworkResponse networkResponse = mNetwork.performRequest(request);
  28. request.addMarker("network-http-complete");
  29. // 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过
  30. if (networkResponse.notModified && request.hasHadResponseDelivered()) {
  31. //如果是相同的请求,那么服务器就返回一次响应
  32. request.finish("not-modified");
  33. continue;
  34. }
  35. // 解析响应数据,返回Response对象
  36. Response<?> response = request.parseNetworkResponse(networkResponse);
  37. request.addMarker("network-parse-complete");
  38. // 根据request的shouldCache字段来判断是不是需要缓存,如果需要,则将其放到mCache中。
  39. if (request.shouldCache() && response.cacheEntry != null) {
  40. // 缓存数据
  41. mCache.put(request.getCacheKey(), response.cacheEntry);
  42. request.addMarker("network-cache-written");
  43. }
  44. // 标记请求已经被分发
  45. request.markDelivered();
  46. //调用 mDelivery将Response对象传回主线程进行UI的更新。
  47. mDelivery.postResponse(request, response);
  48. } catch (VolleyError volleyError) {
  49. volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
  50. parseAndDeliverNetworkError(request, volleyError);
  51. } catch (Exception e) {
  52. VolleyLog.e(e, "Unhandled exception %s", e.toString());
  53. VolleyError volleyError = new VolleyError(e);
  54. volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
  55. //有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示
  56. mDelivery.postError(request, volleyError);
  57. }
  58. }
  59. }

网络线程(NetworkDispatcher)主要做了几件事情:
1)调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。
2)判断请求有没有被取消,如果被取消,则重新获取请求。
3)调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。
4)调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。
5)判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。
6)调用 mDelivery将Response对象传到主线程中进行UI更新。

此处输入图片的描述

quit方法:

  1. //用于判断线程是否结束,用于退出线程
  2. private volatile boolean mQuit = false;
  3. //出线程
  4. public void quit() {
  5. mQuit = true;
  6. interrupt();
  7. }

关于volatile,建议阅读:volatile型变量的特殊访问规则

quit方法的作用是中断当前的网络请求线程。quit方法中做的事情就是对中断标志位置位,同时调用interrupt()方法中断当前的网络请求线程,我们知道mQueue是一个阻塞队列,所以当没有请求的时候,take方法会阻塞网络请求线程,这时候调用interrupt()方法会抛出InterruptedException异常,这样代码就会进入catch代码块,这时候由于中断标志位已经被置位了,所以会执行return语句,结束while循环,当前的网络请求线程,就终止运行了。

  1. while (true) {
  2. Request<?> request;
  3. try {
  4. request = mQueue.take();
  5. } catch (InterruptedException e) {
  6. if (mQuit) {
  7. return;
  8. }
  9. continue;
  10. }
  11. }

Volley源码分析(三)NetWorkDispatcher分析
Android中关于Volley的使用(七)认识 NetworkDispatcher 和 BasicNetwork

Volley源码解析<五> CacheDispatcher和NetworkDispatcher

Android中TrafficStats流量监控类

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注