AndroidAndroid开发经验谈Android开发

01 Volley源码解析

2021-08-19  本文已影响0人  凤邪摩羯

Volley 是 Google 2013年推出的 Android 异步网络请求框架和图片加载框架。主要适用于数据量小,但通信频繁的网络请求(移动端的网络请求多为这种类型)。

Volley的使用非常简单,首先通过调用Volley的静态方法newRequestQueue获得并开启一个请求队列,然后创建一个Request对象,将该Request对象加入到请求队列中便可以执行网络请求了,然后可以通过监听Response类中的Listener和ErrorListener获得请求结果。

Volley框架中数据结构:

  1. 队列:一个网络请求队列(PriorityBlockingQueue)、一个缓存队列(PriorityBlockingQueue,存储Cache对象)和一个等待队列(Map<String, Queue<Request<?>>>),网络请求队列用于存放网络请求,缓存请求队列用于存放缓存请求,而等待队列则是一个用于存放可以走缓存请求的指向同一URL请求的请求队列,其键为cacheKey,值为cacheKey相同的请求构成的队列(cacheKey其实就是请求的URL,所以就是相同URL请求构成的队列),也就是说Volley对指向同一个URL的请求进行了优化,通过将这些请求加入到同一个队列中,这样就可以避免重复对同一个URL发送请求,既可以提高程序效率,也可以提高内存利用率;
  2. 线程:主线程、缓存线程(CacheDispatcher)和网络请求线程(NetworkDispatcher);主线程默认为调用Volley执行网络请求的activity所在的main线程,缓存线程则用于执行从缓存队列中取出的缓存请求,网络请求线程负责执行从网络请求队列中取出的网络请求;这三个线程的切换由ResponseDelivery的实现类来执行,默认为ExecutorDelivery,该实现类内部封装了一个Handler,通过Handler的post方法完成线程切换;默认情况下,在我们通过requestQueue的start方法开启网络请求时,Volley会创建一个缓存线程和四个网络线程(点评:感觉这个地方可以改进一下,比如说可以根据当前机器的CPU核数来决定网络请求的个数等)

Volley网络请求的具体过程
首先获取一个RequestQueue对象,然后调用该RequestQueue对象的add方法将一个Request加入到这个请求队列中。在RequestQueue的add方法中,首先会判断该Request是否可以被缓存,如果不行的话,就直接将该请求加入到网络请求队列中,让其通过网络请求分发器走网络请求处理流程就好了;如果这是一个可以被缓存的请求的话,那么首先会根据该请求的URL来判断当前等待队列中是否有指向同一个URL的请求,如果有,就将该请求加入到同一URL请求所指向的队列中;如果没有,则先将该请求加入到等待队列中,然后将其加入到缓存队列中。请求被加入到不同的队列中后就会通过不同的请求分发器进行处理。

下面首先分析下缓存分发器(线程)的处理流程:缓存分发器的run方法中有一个while死循环,通过这个循环不断从缓存队列中取出请求进行处理直至遇到一个标志应该退出队列的异常(InterruptedException)。在循环内部,首先会从缓存队列中取出一个请求,如果该请求已被取消,则继续取出下一个请求进行处理;如果未被取消,则看该请求对应的响应数据是否已经缓存队列中,如果不在缓存队列中,则将该请求加入到网络请求队列中去走网络请求;如果该请求缓存命中,但是已经完全(硬)过期,也将其加入到网络请求队列中,因为硬过期的缓存数据已经不可用了;如果该请求缓存命中,且未过期,便通过ResponseDelivery从缓存线程中切换到主线程中,同时将该请求及请求结果通过响应结果分发器(ResponseDelivery)提交给主线程;如果该请求缓存命中,但是已经软过期,那么通过分发器将当前请求结果提交给主线程,同时将该请求加入到网络请求队列中,用于数据刷新。

从缓存请求队列的处理流程可以看出Google为我们提供了一个很好的编程范式:不仅对请求进行缓存,而且还将缓存结果的过期状态分为软过期和硬过期两种,这两种状态是通过Response的isExpired()方法和refreshNeeded()方法来判断,当前者为true时,为硬过期;当前者为false,而后者为true时,为软过期,软过期时Response中boolean类型的intermediate标志将被设为true;软过期的数据会先返回给用户,然后将对应的请求加入到网络请求队列中用于数据刷新;硬过期则直接将其加入到网络请求队列中。

接下来看网络请求是如何被处理的。网络请求线程的run方法首先会将该线程设为后台线程,然后也是通过一个while死循环处理请求直至遇到一个标志应该退出队列的异常或请求出错。从网络请求队列中取出一个请求后,如果该请求被取消则继续处理下一个请求;否则通过NetWork的performRequest方法具体执行网络请求,取出请求结果。如果请求结果响应码为304并且该结果已经提交给用户了,那么继续处理下一个请求就好了;否则如果该请求可以缓存,则将结果缓存,然后再通过ResponseDelivery切换回主线程。NetWork的performRequest方法内部会根据当前系统为Android2.3以前还是以后的系统分别调用HttpClient和HttpUrlConnection执行网络请求。

image image
上一篇下一篇

猜你喜欢

热点阅读