如何使用volley框架下载 自定义缓存路径

Volley网络框架完全解析(缓存篇)
Volley网络框架完全解析(缓存篇)
在上一篇中讲完了Volley框架怎么使用,那么这篇就来讲讲Volley框架的缓存机制
我们看Volley内部源码发现:
Volley框架内部自己处理了DiskBasedCache硬盘缓存,但是没有处理LruCache内存缓存,因为一般在处理图片的问题上才更多的用到LruCache缓存,但是它提供了一个ImageCache接口供我们自己实现,该接口默认需要实现两个方法:getBitmap(String key)和putBitmap(String key, Bitmap bitmap),由此可见,这就是从缓存中拿数据和存入数据的两个方法,我们完全可以使用LruCache来实现内存缓存
好了,我们知道了Volley内部的缓存策略,那么Volley的硬盘缓存的缓存目录在哪里呢?Volley缓存哪些数据,是图片还是json还是普通字符串数据?带着这些问题,我们首先就是看源码。
Volley的缓存目录
我们从源码中发现创建一个请求队列的同时,会同时创建Volley的缓存目录和DiskBasedCache缓存对象,我们可以得知Volley的缓存目录就是在我们应用内置的cacheDir目录下的volley文件夹中,然后把这个目录用作DiskBasedCache硬盘缓存的目录,源码如下:
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), &volley&);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
于是,我们打开文件管理器发现缓存目录确实是在里面:
Volley缓存的数据
Volley缓存的数据其实包括字符串数据、json数据、图片等,它可以缓存我们请求得到的数据
Volley加载图片的方案
Volley为我们提供了多种加载图片的方法:
1、使用ImageRequest
2、使用ImageLoader
3、使用ImageLoader+NetworkImageView
它们的使用我在上一篇Volley的使用篇就说过了,现在主要讲讲它们分别适合的运用场景和原理
1、使用ImageRequest,适用在图片数量不多的情况下,并且它本身内部可以处理图片的压缩和图片质量的配置,构造方法为:
/** * @url 请求url * @listener 请求成功回调的接口 * @maxWidth 图片最大的宽度(如果超过则Volley会对图片进行压缩,如果为0则不压缩) * @maxHeight 图片最大的高度 * @decodeConfig 图片的配置 * @errorListener 请求失败回调的接口 */
public ImageRequest(String url, Listener&Bitmap& listener, int maxWidth, int maxHeight, Config decodeConfig, ErrorListener errorListener)
2、使用ImageLoader,适用在图片数量多的情况下,同时它使用get()方法在加载图片时候根据情况也可以对图片进行压缩处理,get()方法参数为:
/** * @requestUrl - 请求url * @listener - ImageLoader.ImageListener的监听对象 * @maxWidth - 图片的最大高度,如果超过则会压缩,为0则不压缩 * @maxHeight */
public ImageLoader.ImageContainer get(String requestUrl, ImageLoader.ImageListener listener, int maxWidth, int maxHeight)
ImageLoader构造方法为:
/** *@queue 请求队列 *@imageCache 实现了ImageCache接口的缓存对象 */
public ImageLoader(RequestQueue queue, ImageLoader.ImageCache imageCache)
3、使用ImageLoader+NetworkImageView,在上一个方法中,我们同样也是使用了ImageLoader,不过这个方法我们是使用Volley提供的NetworkImageView来显示图片的,为什么使用它呢?因为它会自动管理本身请求的生命周期,当NetworkImageView退出屏幕时或者Activity退出时候,它会自动取消网络请求,从而节约资源。同样,该方法适合用在图片数量多的情况下,同时它也有对图片压缩的处理方法,就是通过在layout.xml布局文件中设置它的宽高,加载图片的时候会根据图片的大小和设定的宽高进行压缩的。
&com.android.volley.toolbox.NetworkImageView
android:layout_width=&100dp&
android:layout_height=&100dp&
那为什么NetworkImageView可以直接使用setImageUrl(url, mImageLoader);方法直接设置图片呢?因为这个方法内部是通过调用ImageLoader中的get()方法来请求得到图片的,所以原理和ImageLoader加载图片是一样的,只不过它对网络请求的生命周期进行了更好的管理。
【总结】:所以,综上所述,我们可以更据不同的需求来采取不同的方法,可见Volley对图片的加载策略还是非常的强大的。
Volley的缓存机制
Volley缓存到底是怎样的呢?首先,我们通过一个实例来看,这个实例中我使用JsonObjectRequest来请求json数据,使用ImageRequest来加载三张图片,使用ImageLoader+NetworkImageView来加载另外三张图片,我们运行一下可以看到这个效果:
可以看到图片和json数据都加载出来了,那么这些数据是不是都会缓存到cacheDir-&volley目录下呢?当然会了,因为Volley默认情况下都会保存缓存数据到volley缓存目录下的,我们打开volley目录:
发现确实存在七个缓存文件,说明了我们的json数据也缓存了,其中以“-”开头的文件就是我们图片的缓存文件,而另外一个则是json数据字符串的缓存文件,那么这些缓存文件的内容是什么呢?我们首先打开其中一个图片缓存文件,内容如下:
我们从文件内容中很难看懂里面的大部分内容,不过开头的那部分我们还是能看懂的,上面我标记了的三个表示的内容分别是:图片请求的url地址、图片的名称、图片的大小。后面那部分乱码的内容其实就是图片的内容。
我们再打开缓存json数据的那个文件,内容如下:
(责任编辑:lengtong)
------分隔线----------------------------
iOS图标适配:...
1,安装JDK: sudo apt-get install aptitude sudo aptitude search openjava sudo ap...
动态隐藏头部:比如:需求是首页是不需要头部标题的,其他页面就需要,那么加上hide-na...
个 推荐 5 个反对。结果大大的出乎我的预料。我是做好了被狂喷群殴准备的,因为我认为...
性能是苹果审核的一个很重要的部分,CPU,内存,图形绘制,存储空间和网络性能都是应...
创业的第十八天:今天把详细设计说明书写出来了,基于个人的水平有限,有些地方真的写...使用Volley加载、缓存图片(ImageLoader) - 简书
下载简书移动应用
写了19309字,被258人关注,获得了509个喜欢
使用Volley加载、缓存图片(ImageLoader)
关键字:图片缓存 LruCache ImageCache NetworkImageView ImageRequest ImageLoader
前言: 记录了Volley的简单用法,进行简单的GET、POST请求。这篇文章将记录Volley加载、缓存图片的用法。
Volley还可以进行图片的加载和缓存,可以利用ImageRequest对象简单、方便地进行网络图片的获取。ImageLoader用于获取或缓存图片。NetworkImageView是Volley提供的一个自定义View,可直接设置网络图片。
1. 使用ImageRequest简单地进行网络图片的获取
String url = "/photo-9-d158eaa028a6?fit=crop&fm=jpg&h=625&ixlib=rb-0.3.5&q=80&w=1375";
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
//构建ImageRequest 实例
ImageRequest request = new ImageRequest(url, new Response.Listener&Bitmap&() {
public void onResponse(Bitmap response) {
//给imageView设置图片
myImageView.setImageBitmap(response);
}, 0, 0, ImageView.ScaleType.CENTER, Bitmap.Config.RGB_565, new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
//设置一张错误的图片,临时用ic_launcher代替
myImageView.setImageResource(R.drawable.ic_launcher);
requestQueue.add(request);
注意:在构建ImageRequest实例时,需要传递七个参数(六个参数的重载方法已过时,少一个ScaleType参数)这七个参数类型分别为:
String : 要获取的图片地址
Response.Listener&Bitmap& : 获取图片成功的回调
int: maxWidth,获取图片的最大宽度,会自动进行压缩或拉伸,设置为0,即获取原图
int :maxHeight,同上
ScaleType :显示的类型,居中,平铺等
Config:图片类型,如:Bitmap.Config.RGB_565
Response.ErrorListener: 获取图片失败的回调
2. 使用ImageLoader缓存网络图片
使用ImageLoader只需三步:
实例化ImageLoader
设置监听器
代码如下:MainActivity.java文件:
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
//1.实例化ImageLoader
ImageLoader loader = new ImageLoader(requestQueue, new BitmapCache());
//2.设置监听器
ImageLoader.ImageListener listener =
ImageLoader.getImageListener(myImageView, R.drawable.ic_launcher, R.drawable.ic_launcher);
//3.获取图片
loader.get(url, listener);
BitmapCache.java文件:
public class BitmapCache implements ImageLoader.ImageCache {
//LruCache对象
private LruCache&String, Bitmap& lruC
//设置最大缓存为10Mb,大于这个值会启动自动回收
private int max = 10*;
public BitmapCache(){
//初始化 LruCache
lruCache = new LruCache&String, Bitmap&(max){
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
public Bitmap getBitmap(String url) {
return lruCache.get(url);
public void putBitmap(String url, Bitmap bitmap) {
lruCache.put(url, bitmap);
ImageLoader构造器需要两个参数,requestQueue是熟悉的请求队列,imageCache是图片缓存对象,需要自定义类实现imageCache对象。使用LruCache来作为具体的图片缓存对象。
ImageLoader.getImageListener()需要三个参数:ImageView实例,默认的图片资源,错误显示的图片资源
ImageLoader调用get(ImageURL, listener)方法,获取图片
3. NetworkImageView的使用
layout_main.xml文件:
&?xml version="1.0" encoding="utf-8"?&
&RelativeLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_horizontal_margin"
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="获取图片"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" /&
&com.android.volley.toolbox.NetworkImageView
android:id="@+id/mNetworkImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" /&
&/RelativeLayout&
BitmapCache.java文件:同“使用ImageLoader缓存网络图片”。
MainActivity.java文件:
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
//实例化ImageLoader
ImageLoader loader = new ImageLoader(requestQueue, new BitmapCache());
//设置默认图片
mNetworkImageView.setDefaultImageResId(R.drawable.ic_launcher);
//设置错误图片
mNetworkImageView.setErrorImageResId(R.drawable.ic_launcher);
//设置图片url和ImageLoader
mNetworkImageView.setImageUrl(url,loader);
据说打赏我的人,最后都成为了IT大牛!!!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
简书程序员大本营
投稿须知:
1.本专题仅收录与程序有关的文章。
2.请在代码框里写代码,尽量保证可看性。
· 53635人关注
弱水三千,只取一瓢饮
· 932人关注
安卓技术知识
· 533人关注
据说打赏我的人,最后都成为了IT大牛!!!
选择支付方式:酷勤网 C 程序员的那点事!
当前位置: >
浏览次数:次
虽然网上已经有很多大神、高手都写过了类似的帖子,但作为新人,必须要走模仿的道路,再考虑超越,因此学习大神的笔记,记录自己的理解,是一个菜鸟走向成功的必经之路啊。如签名所言,记录自己摸爬滚打的经历,享受不悔的青春。废话不多说,言归正传。
二、Volley是什么?
Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架。
三、Volley的主要特性
(1). 扩展性强。Volley 中大多是基于接口的设计,可配置性强。
(2). 一定程度符合 Http 规范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
(3). 默认 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现,这两者的区别及优劣在4.2.1 Volley中具体介绍。
(4). 提供简便的图片加载工具。
四、volley的总体设计图
上图源自网络。如上图所示,volley主要是通过两种Diapatch Thread不断从RequestQueue中取出请求,根据是否已缓存调用Cache或Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据,然后交由ResponseDelivery去做结果分发及回调处理。
五、volley中的一些概念
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 中取缓存结果。
六、volley请求处理流程图
上图源自网络。
七、volley的类图
为了更好的理解volley,类图是必不可少的一个参照图
八、volley工程结构
volley的是开源项目,其工程结构如上图所示。
九、核心功能类介绍
Volley.java
(1). 主要函数
Volley.java 有两个重载的静态方法。
publicstaticRequestQueuenewRequestQueue(Contextcontext)
publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack)
第一个方法的实现调用了第二个方法,传 HttpStack 参数为 null。
第二个方法中,如果 HttpStatck 参数为 null,则如果系统在 Gingerbread 及之后(即 API Level &= 9),采用基于 HttpURLConnection 的 HurlStack,如果小于 9,采用基于 HttpClient 的 HttpClientStack。
if(stack==null){
if(Build.VERSION.SDK_INT&=9){
stack=newHurlStack();
stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
得到了 HttpStack,然后通过它构造一个代表网络(Network)的具体实现BasicNetwork。
接着构造一个代表缓存(Cache)的基于 Disk 的具体实现DiskBasedCache。
最后将网络(Network)对象和缓存(Cache)对象传入构建一个 RequestQueue,启动这个 RequestQueue,并返回。
Networknetwork=newBasicNetwork(stack);
RequestQueuequeue=newRequestQueue(newDiskBasedCache(cacheDir),network);
queue.start();
平时大多采用Volly.newRequestQueue(context)的默认实现,构建RequestQueue。
通过源码可以看出,我们可以抛开 Volley 工具类构建自定义的RequestQueue,采用自定义的HttpStatck,采用自定义的Network实现,采用自定义的Cache实现等来构建RequestQueue。
(2). HttpURLConnection 和 AndroidHttpClient(HttpClient 的封装)如何选择及原因:
在 Froyo(2.2) 之前,HttpURLConnection 有个重大 Bug,调用 close() 函数会影响连接池,导致连接复用失效,所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive。
另外在 Gingerbread(2.3) HttpURLConnection 默认开启了 gzip 压缩,提高了 HTTPS 的性能,Ice Cream Sandwich(4.0) HttpURLConnection 支持了请求结果缓存。
再加上 HttpURLConnection 本身 API 相对简单,所以对 Android 来说,在 2.3 之后建议使用 HttpURLConnection,之前建议使用 AndroidHttpClient。
Request.java
代表一个网络请求的抽象类。我们通过构建一个Request类的非抽象子类(StringRequest、JsonRequest、ImageRequest或自定义)对象,并将其加入到&RequestQueue&中来完成一次网络请求操作。
Volley 支持 8 种 Http 请求方式 GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, PATCH
Request 类中包含了请求 url,请求请求方式,请求 Header,请求 Body,请求的优先级等信息。
因为是抽象类,子类必须重写的两个方法。
abstractprotectedResponse&T&parseNetworkResponse(NetworkResponseresponse);
子类重写此方法,将网络返回的原生字节内容,转换成合适的类型。此方法会在工作线程中被调用。
abstractprotectedvoiddeliverResponse(Tresponse);
子类重写此方法,将解析成合适类型的内容传递给它们的监听回调。
以下两个方法也经常会被重写
publicbyte[]getBody()
重写此方法,可以构建用于 POST、PUT、PATCH 请求方式的 Body 内容。
protectedMap&String,String&getParams()
在上面getBody函数没有被重写情况下,此方法的返回值会被 key、value 分别编码后拼装起来转换为字节码作为 Body 内容。
RequestQueue.java
Volley 框架的核心类,将请求Request加入到一个运行的RequestQueue中,来完成请求操作。
(1). 主要成员变量
RequestQueue 中维护了两个基于优先级的 Request 队列,缓存请求队列和网络请求队列。
放在缓存请求队列中的 Request,将通过缓存获取数据;放在网络请求队列中的 Request,将通过网络获取数据。
privatefinalPriorityBlockingQueue&Request&?&&mCacheQueue=newPriorityBlockingQueue&Request&?&&();
privatefinalPriorityBlockingQueue&Request&?&&mNetworkQueue=newPriorityBlockingQueue&Request&?&&();
维护了一个正在进行中,尚未完成的请求集合。
privatefinalSet&Request&?&&mCurrentRequests=newHashSet&Request&?&&();
维护了一个等待请求的集合,如果一个请求正在被处理并且可以被缓存,后续的相同 url 的请求,将进入此等待队列。
privatefinalMap&String,Queue&Request&?&&&mWaitingRequests=newHashMap&String,Queue&Request&?&&&();
(2). 启动队列
创建出 RequestQueue 以后,调用 start 方法,启动队列。
*Startsthedispatchersinthisqueue.
publicvoidstart(){
stop();//Makesureanycurrentlyrunningdispatchersarestopped.
//Createthecachedispatcherandstartit.
mCacheDispatcher=newCacheDispatcher(mCacheQueue,mNetworkQueue,mCache,mDelivery);
mCacheDispatcher.start();
//Createnetworkdispatchers(andcorrespondingthreads)uptothepoolsize.
for(inti=0;i&mDispatchers.i++){
NetworkDispatchernetworkDispatcher=newNetworkDispatcher(mNetworkQueue,mNetwork,
mCache,mDelivery);
mDispatchers[i]=networkD
networkDispatcher.start();
start 方法中,开启一个缓存调度线程CacheDispatcher和 n 个网络调度线程NetworkDispatcher,这里 n 默认为4,存在优化的余地,比如可以根据 CPU 核数以及网络类型计算更合适的并发数。
缓存调度线程不断的从缓存请求队列中取出 Request 去处理,网络调度线程不断的从网络请求队列中取出 Request 去处理。
(3). 加入请求
public&T&Request&T&add(Request&T&request);
流程图如下:
(4). 请求完成
voidfinish(Request&?&request)
Request 请求结束
(1). 首先从正在进行中请求集合mCurrentRequests中移除该请求。
(2). 然后查找请求等待集合mWaitingRequests中是否存在等待的请求,如果存在,则将等待队列移除,并将等待队列所有的请求添加到缓存请求队列中,让缓存请求处理线程CacheDispatcher自动处理。
(5). 请求取消
publicvoidcancelAll(RequestFilterfilter)
publicvoidcancelAll(finalObjecttag)
取消当前请求集合中所有符合条件的请求。
filter 参数表示可以按照自定义的过滤器过滤需要取消的请求。
tag 表示按照Request.setTag设置好的 tag 取消请求,比如同属于某个 Activity 的。
CacheDispatcher.java
一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。
(1). 成员变量
BlockingQueue&Request&?&& mCacheQueue缓存请求队列
BlockingQueue&Request&?&& mNetworkQueue网络请求队列
Cache mCache缓存类,代表了一个可以获取请求结果,存储请求结果的缓存
ResponseDelivery mDelivery请求结果传递类
(2). 处理流程图
NetworkDispatcher.java
一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给 ResponseDelivery 去执行后续处理,并判断结果是否要进行缓存。
(1). 成员变量
BlockingQueue&Request&?&& mQueue网络请求队列
Network mNetwork网络类,代表了一个可以执行请求的网络
Cache mCache缓存类,代表了一个可以获取请求结果,存储请求结果的缓存
ResponseDelivery mDelivery请求结果传递类,可以传递请求的结果或者错误到调用者
Cache.java
缓存接口,代表了一个可以获取请求结果,存储请求结果的缓存。
(1). 主要方法:
public Entry get(String key);通过 key 获取请求的缓存实体
public void put(String key, Entry entry);存入一个请求的缓存实体
public void remove(String key);移除指定的缓存实体
public void clear();清空缓存
(2). 代表缓存实体的内部类 Entry
成员变量和方法
byte[] data请求返回的数据(Body 实体)
String etagHttp 响应首部中用于缓存新鲜度验证的 ETag
long serverDateHttp 响应首部中的响应产生时间
long ttl缓存的过期时间
long softTtl缓存的新鲜时间
Map&String, String& responseHeaders响应的 Headers
boolean isExpired()判断缓存是否过期,过期缓存不能继续使用
boolean refreshNeeded()判断缓存是否新鲜,不新鲜的缓存需要发到服务端做新鲜度的检测
DiskBasedCache.java
继承 Cache 类,基于 Disk 的缓存实现类。
(1). 主要方法:
public synchronized void initialize()初始化,扫描缓存目录得到所有缓存数据摘要信息放入内存。
public synchronized Entry get(String key)从缓存中得到数据。先从摘要信息中得到摘要信息,然后读取缓存数据文件得到内容。
public synchronized void put(String key, Entry entry)将数据存入缓存内。先检查缓存是否会满,会则先删除缓存中部分数据,然后再新建缓存文件。
private void pruneIfNeeded(int neededSpace)检查是否能再分配 neededSpace 字节的空间,如果不能则删除缓存中部分数据。
public synchronized void clear()清空缓存。
public synchronized void remove(String key)删除缓存中某个元素。
(2). CacheHeader 类
CacheHeader 是缓存文件摘要信息,存储在缓存文件的头部,与上面的Cache.Entry相似。
NoCache.java
继承 Cache 类,不做任何操作的缓存实现类,可将它作为构建RequestQueue的参数以实现一个不带缓存的请求队列。
Network.java
代表网络的接口,处理网络请求。
唯一的方法,用于执行特定请求。
publicNetworkResponseperformRequest(Request&?&request)throwsVolleyE
NetworkResponse.java
Network中方法 performRequest 的返回值,Request的 parseNetworkResponse(&) 方法入参,是 Volley 中用于内部 Response 转换的一级。
封装了网络请求响应的 StatusCode,Headers 和 Body 等。
(1). 成员变量
int statusCodeHttp 响应状态码
byte[] dataBody 数据
Map&String, String& headers响应 Headers
boolean notModified表示是否为 304 响应
long networkTimeMs请求耗时
(2). Volley 的内部 Response 转换流程图
BasicNetwork.java
实现 Network,Volley 中默认的网络接口实现类。调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
主要实现了以下功能:
(1). 利用 HttpStack 执行网络请求。
(2). 如果 Request 中带有实体信息,如 Etag,Last-Modify 等,则进行缓存新鲜度的验证,并处理 304(Not Modify)响应。
(3). 如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束。
HttpStack.java
用于处理 Http 请求,返回请求结果的接口。目前 Volley 中的实现有基于 HttpURLConnection 的 HurlStack 和 基于 Apache HttpClient 的 HttpClientStack。
唯一方法,执行请求
public HttpResponse performRequest(Request&?& request, Map&String, String& additionalHeaders)
throws IOException, AuthFailureE
执行 Request 代表的请求,第二个参数表示发起请求之前,添加额外的请求 Headers。
HttpClientStack.java
实现 HttpStack 接口,利用 Apache 的 HttpClient 进行各种请求方式的请求。
基本就是 org.apache.http 包下面相关类的常见用法,不做详解,不过与下面 HttpURLConnection 做下对比就能发现 HttpURLConnection 的 API 相对简单的多。
HurlStack.java
实现 HttpStack 接口,利用 Java 的 HttpURLConnection 进行各种请求方式的请求。
Response.java
封装了经过解析后的数据,用于传输。并且有两个内部接口 Listener 和 ErrorListener 分别可表示请求失败和成功后的回调。
Response 的构造函数被私有化,而通过两个函数名更易懂的静态方法构建对象。
ByteArrayPool.java
byte[] 的回收池,用于 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[]。
PoolingByteArrayOutputStream.java
继承ByteArrayOutputStream,原始 ByteArrayOutputStream 中用于接受写入 bytes 的 buf,每次空间不足时便会 new 更大容量的 byte[],而 PoolingByteArrayOutputStream 使用了 ByteArrayPool 作为 Byte[] 缓存来减少这种操作,从而提高性能。
HttpHeaderParser.java
Http header 的解析工具类,在 Volley 中主要作用是用于解析 Header 从而判断返回结果是否需要缓存,如果需要返回 Header 中相关信息。
有三个方法
publicstaticlongparseDateAsEpoch(StringdateStr)
解析时间,将 RFC1123 的时间格式,解析成 epoch 时间
publicstaticStringparseCharset(Map&String,String&headers)
解析编码集,在 Content-Type 首部中获取编码集,如果没有找到,默认返回 ISO-8859-1
publicstaticCache.EntryparseCacheHeaders(NetworkResponseresponse)
比较重要的方法,通过网络响应中的缓存控制 Header 和 Body 内容,构建缓存实体。如果 Header 的 Cache-Control 字段含有no-cache或no-store表示不缓存,返回 null。
(1). 根据 Date 首部,获取响应生成时间
(2). 根据 ETag 首部,获取响应实体标签
(3). 根据 Cache-Control 和 Expires 首部,计算出缓存的过期时间,和缓存的新鲜度时间
两点需要说明下:
1.没有处理Last-Modify首部,而是处理存储了Date首部,并在后续的新鲜度验证时,使用Date来构建If-Modified-Since。 这与 Http 1.1 的语义有些违背。
2.计算过期时间,Cache-Control 首部优先于 Expires 首部。
RetryPolicy.java
重试策略接口
有三个方法:
public int getCurrentTimeout();
获取当前请求用时(用于Log)
public int getCurrentRetryCount();
获取已经重试的次数(用于Log)
public void retry(VolleyError error) throws VolleyE
确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。
DefaultRetryPolicy.java
实现 RetryPolicy,Volley 默认的重试策略实现类。主要通过在 retry(&) 函数中判断重试次数是否达到上限确定是否继续重试。
其中mCurrentTimeoutMs变量表示已经重试次数。
mBackoffMultiplier表示每次重试之前的 timeout 该乘以的因子。
mCurrentTimeoutMs变量表示当前重试的 timeout 时间,会以mBackoffMultiplier作为因子累计前几次重试的 timeout。
ResponseDelivery.java
请求结果的传输接口,用于传递请求结果或者请求错误。
有三个方法:
publicvoidpostResponse(Request&?&request,Response&?&response);
此方法用于传递请求结果,request和response参数分别表示请求信息和返回结果信息。
publicvoidpostResponse(Request&?&request,Response&?&response,Runnablerunnable);
此方法用于传递请求结果,并在完成传递后执行 Runnable。
publicvoidpostError(Request&?&request,VolleyErrorerror);
此方法用于传输请求错误。
ExecutorDelivery.java
请求结果传输接口具体实现类。
在 Handler 对应线程中传输缓存调度线程或者网络调度线程中产生的请求结果或请求错误,会在请求成功的情况下调用 Request.deliverResponse(&) 函数,失败时调用 Request.deliverError(&) 函数。
StringRequest.java
继承 Request 类,代表了一个返回值为 String 的请求。将网络返回的结果数据解析为 String 类型。通过构造函数的 listener 传参,支持请求成功后的 onResponse(&) 回调。
JsonRequest.java
抽象类,继承自 Request,代表了 body 为 JSON 的请求。提供了构建 JSON 请求参数的方法。
JsonObjectRequest.java
继承自 JsonRequest,将网络返回的结果数据解析为 JSONObject 类型。
JsonArrayRequest.java
继承自 JsonRequest,将网络返回的结果数据解析为 JSONArray 类型。
ImageRequest.java
继承 Request 类,代表了一个返回值为 Image 的请求。将网络返回的结果数据解析为 Bitmap 类型。
可以设置图片的最大宽度和最大高度,并计算出合适尺寸返回。每次最多解析一张图片防止 OOM。
ImageLoader.java
封装了 ImageRequst 的方便使用的图片加载工具类。
1.可以设置自定义的ImageCache,可以是内存缓存,也可以是 Disk 缓存,将获取的图片缓存起来,重复利用,减少请求。
2.可以定义图片请求过程中显示的图片和请求失败后显示的图片。
3.相同请求(相同地址,相同大小)只发送一个,可以避免重复请求。
NetworkImageView.java
利用 ImageLoader,可以加载网络图片的 ImageView
有三个公开的方法:
publicvoidsetDefaultImageResId(intdefaultImage)
设置默认图片,加载图片过程中显示。
publicvoidsetErrorImageResId(interrorImage)
设置错误图片,加载图片失败后显示。
publicvoidsetImageUrl(Stringurl,ImageLoaderimageLoader)
设置网络图片的 Url 和 ImageLoader,将利用这个 ImageLoader 去获取网络图片。
如果有新的图片加载请求,会把这个ImageView上旧的加载请求取消。
ClearCacheRequest.java
用于人为清空 Http 缓存的请求。
添加到 RequestQueue 后能很快执行,因为优先级很高,为Priority.IMMEDIATE。并且清空缓存的方法mCache.clear()写在了isCanceled()方法体中,能最早的得到执行。
ClearCacheRequest 的写法不敢苟同,目前看来唯一的好处就是可以将清空缓存操作也当做一个请求。而在isCanceled()中做清空操作本身就造成了歧义,不看源码没人知道在NetworkDispatcherrun 方法循环的过程中,isCanceled()这个读操作竟然做了可能造成缓存被清空。只能跟源码的解释一样当做一个 Hack 操作。
Authenticator.java
身份认证接口,用于基本认证或者摘要认证。这个类是 Volley 用于和身份验证打通的接口,比如 OAuth,不过目前的使用不是特别广泛和 Volley 的内部结合也不是特别紧密。
AndroidAuthenticator.java
继承 Authenticator,基于 Android AccountManager 的认证交互实现类。
VolleyLog.java
Volley 的 Log 工具类。
VolleyError.java
Volley 中所有错误异常的父类,继承自 Exception,可通过此类设置和获取 NetworkResponse 或者请求的耗时。
AuthFailureError.java
继承自 VolleyError,代表请求认证失败错误,如 RespondeCode 的 401 和 403。
NetworkError.java
继承自 VolleyError,代表网络错误。
ParseError.java
继承自 VolleyError,代表内容解析错误。
ServerError.java
继承自 VolleyError,代表服务端错误。
TimeoutError.java
继承自 VolleyError,代表请求超时错误。
NoConnectionError.java
继承自NetworkError,代表无法建立连接错误。
十、下载地址
QQ讨论群组:
& 相关主题:

我要回帖

更多关于 volley框架上传图片 的文章

 

随机推荐