Volley 源码解析

来源:互联网 发布:凸包问题数据 编辑:程序博客网 时间:2024/06/05 17:30

volley框架 是基于 接口 的框架 拥有很高的拓展性多用组合,少用继承;针对接口编程,不针对具体实现编程。优秀框架的设计,令人叫绝,受益良多。


Volley框架的总体设计:1.请求队列2.缓存 还是非缓存3.网络事件分发4.处理数据


volley的网络请求流程 通过请求队列请求网络 然后判断一下是否有缓存,如果有缓存就走缓存的路线 没有就走非缓存路线(各有一个线程处理)然后根据是否是缓存 调用响应的处理接口 最后进行结果处理和事件回调 并且 volley中加入了失败重新请求处理 Volley 中的概念简单介绍一些概念,在详细设计中会仔细介绍。Volley 的调用比较简单,通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue后,只需要往这个RequestQueue不断 add Request 即可。Volley:Volley 对外暴露的 API,通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue。Request:表示一个请求的抽象类。StringRequest、JsonRequest、ImageRequest 都是它的子类,表示某种类型的请求。 RequestQueue:表示请求队列,里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、NetworkDispatcher数组(用于处理走网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 函数启动时会启动CacheDispatcher和NetworkDispatchers。CacheDispatcher:一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。NetworkDispatcher:一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。ResponseDelivery:返回结果分发接口,目前只有基于ExecutorDelivery的在入参 handler 对应线程内进行分发。HttpStack:处理 Http 请求,返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack。Network:调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。Cache:缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。这其中的主要内容都是可以通过实现接口自定义适合自己的网络请求



框架主要类 介绍

1.volley


在该类中 有 2个方法 newRequestQueue(Context context) newRequestQueue(Context context,HttpStack stack)其中一个参数的方法调用了两个参数的方法 讲第二个参数 传null2个参数的newRequestQueue方法 用 DiskBasedCache 和 BasicNetwork 构建了一个RequestQueue


2.Request


因为是抽象类,子类必须重写的两个方法。abstract protected Response<T> parseNetworkResponse(NetworkResponse response);子类重写此方法,将网络返回的原生字节内容,转换成合适的类型。此方法会在工作线程中被调用。abstract protected void deliverResponse(T response);子类重写此方法,将解析成合适类型的内容传递给它们的监听回调。以下两个方法也经常会被重写public byte[] getBody()重写此方法,可以构建用于 POST、PUT、PATCH 请求方式的 Body 内容。protected Map<String, String> getParams()在上面getBody函数没有被重写情况下,此方法的返回值会被 key、value 分别编码后拼装起来转换为字节码作为 Body 内容。


3.RequestQueue


该类为Volley中的核心类RequestQueue 中维护了两个基于优先级的 Request 队列,缓存请求队列和网络请求队列。放在缓存请求队列中的 Request,将通过缓存获取数据;放在网络请求队列中的 Request,将通过网络获取数据。private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>();private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();维护了一个正在进行中,尚未完成的请求集合。private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();维护了一个等待请求的集合,如果一个请求正在被处理并且可以被缓存,后续的相同 url 的请求,将进入此等待队列。private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>();创建出 RequestQueue 以后,调用 start 方法,启动队列。 start 方法中,开启一个缓存调度线程CacheDispatcher和 n 个网络调度线程NetworkDispatcher,这里 n默认为4private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; 属性 当然这里也可以通过 传入 threadPoolSize 进行修改 最好可以根据cpu 数进行修改 如cpu数+1 或者x2+1



4.CacheCache


接口是Volley请求中的 关于缓存的接口 google 基于SD卡实现了一个具体的缓存类 DiskBasedCache.java该类中定义了一个缓存静态实体类 Entry 以及一些接口方法1.public Entry get(String key); 通过key获取请求的缓存实体2.public void put(String key, Entry entry); 存入一个请求的缓存实体3.public void initialize(); 初始化缓存4.public void invalidate(String key, boolean fullExpire); 标记指定的缓存过期 5.public void remove(String key); 移除指定的缓存实体6.public void clear(); 清空缓存google的DiskBasedCache具体实现就不做介绍了 源码中都有注释(基于SD卡的实现)NoCache 没有进行什么操作 如果在构建RequestQueue的时候使用NoCache 可以构建一个无缓存的网络请求队列



5.CacheDispatcher


首先 该类继承子Thread 所以它是一个线程 然后该类名为CacheDispatcher 所以它实际上是一个用于处理缓存队列的线程 首先看一下该类中的属性1.private final BlockingQueue<Request<?>> mCacheQueue; 缓存请求队列2.private final BlockingQueue<Request<?>> mNetworkQueue; 网络请求队列3.private final Cache mCache; 缓存类4.private final ResponseDelivery mDelivery; 请求结果传递类 5.private volatile boolean mQuit = false; 用来停止线程的标志位该类中存在三个方法 1个构造方法 一个quit方法 以及 一个run方法 其中quit方法是通过使用标记位 强行停止该现成的方法(因为在run方法中存在一个while(true)死循环)核心方法 run方法 该类 首先 设置了这个线程的优先级 然后初始化了缓存类(google实现的是基于sd 卡的缓存) 然后剩下的过程都在一个死循环中1.在缓存队列中获取请求2.判断该请求是否被取消(被取消就执行下一个请求-----这里判断的是是否被取消,并不是停止线程的标志位 因此被取消会continue而不是break )3.从缓存队列中 拿到缓存的请求结果 然后判断请求是否有结果 没有结果 就结束该请求 讲该请求放回到网络队列(代码中未找到实现,只是continue,在网上找的流程图上有该部分。。。)4.如果请求结果存在。对该请求结果进行是否过期的判断 如果过期 将该网络请求加入到网络请求中 然后结束该次循环 5.如果请求结果也没有过期 则会进行新鲜度的校验(有些信息是需要经常刷新的 比如 新闻 股票等) 如果该请求结果新鲜,就直接分发结果 。如果该请求结果不新鲜 则仍旧讲该结果分发,同时再进行一次网络请求 刷新缓存在代码中 的catch部分 对mQuit boolean标记位进行判断 是否跳出 该方法



6.NetWork


NetWork 接口 是用于处理 网络请求的一个接口 该接口中只有一个方法performRequest(Request<?> request) 用于处理网络请求google的实现类是BasicNetwork.java该类主要实现了以下功能:(1). 利用 HttpStack 执行网络请求。(2). 如果 Request 中带有实体信息,如 Etag,Last-Modify 等,则进行缓存新鲜度的验证,并处理 304(Not Modify)响应。(3). 如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束。 由此可知 真正进行网络请求操作的是httpStack


7.NetworkDispatcher


NetworkDispatcher 是网络请求的线程 和CacheDispatcher 类似 他们的属性也是1.private final BlockingQueue<Request<?>> mQueue; 网络请求队列2.private final Network mNetwork; 封装了HurlStack的网络类,其performRequest方法是单个request请求真正执行的地方.3.private final Cache mCache; 缓存类,存储请求结果的缓存4.private final ResponseDelivery mDelivery; 请求结果传递类.5.private volatile boolean mQuit = false; 暂停线程的标志位,替换Thread自身的stop方法内部的方法有 5个 其中一个构造方法 一个 quit方法 一个核心run方法 和一个parseAndDeliverNetworkError在这里 就只详细介绍 run方法1.先设置了线程的优先级 然后是一个while(true) 死循环2.从队列中获取一个请求(这里有try catch 如果出现异常则会判断mQuit标志位 是否要退出死循环)3.获取到请求之后 判断一下请求是否被取消了 如果取消就关闭该请求 4.如果请求没有被取消 通过NetworkResponse 执行网络请求 5.然后判断一下当前的网络请求是否是304并且是否已经获取到请求结果 (如果是304则表示服务器响应状态和上次相比未改变) 可以理解为烦会结果和上次 相同 6.如果存在新的信息,则会根据具体的Request 调用期内不得抽象方法parseNetworkResponse 解析数据7.判断一下是否允许缓存 并且 请求结果的缓存实体 不为null 如果符合条件就添加缓存并将结果传递给分发类)(ResponseDelivery),并由该类调用用于设置的回调



8.ResponseResponse类


较为简单 其内部包含 两个接口request 请求成功接口和失败接口 2个静态的构造Response方法 用于构造请求成功和请求失败的Response对象 因为该类内部的构造方法是私有的。。。以及几个属性和 方法 1.public final T result; request的网络请求解析结果2.public final Cache.Entry cacheEntry; request的缓存内容.3.public final VolleyError error; 请求错误内容4.public boolean intermediate = false; 当前结果是否为中间请求结果//返回当前request请求结果是否成功public boolean isSuccess() { return error == null; }



9.其余HttpStack.java用于处理 Http 请求,返回请求结果的接口。目前 Volley 中的实现有基于 HttpURLConnection 的 HurlStack 和 基于 Apache HttpClient 的 HttpClientStack。唯一方法,执行请求public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError;执行 Request 代表的请求,第二个参数表示发起请求之前,添加额外的请求 Headers。HttpClientStack.java实现 HttpStack 接口,利用 Apache 的 HttpClient 进行各种请求方式的请求。基本就是 org.apache.http 包下面相关类的常见用法,不做详解,不过与下面 HttpURLConnection 做下对比就能发现 HttpURLConnection 的 API 相对简单的多。HurlStack.java实现 HttpStack 接口,利用 Java 的 HttpURLConnection 进行各种请求方式的请求。ByteArrayPool.javabyte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。 主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。public synchronized void returnBuf(byte[] buf)将用过的 byte[] 回收,根据 byte[] 长度按照从小到大的排序将 byte[] 插入到缓存中合适位置。public synchronized byte[] getBuf(int len)获取长度不小于 len 的 byte[],遍历缓存,找出第一个长度大于传入参数len的 byte[],并返回;如果最终没有合适的 byte[],new 一个返回。private synchronized void trim()当缓存的 byte 超过预先设置的大小时,按照先进先出的顺序删除最早的 byte[]。

0 0