Android 浅析 Volley (一) 使用

前言

Linus Benedict Torvalds : RTFSC – Read The Funning Source Code

概括

Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster.
Volley excels at RPC-type operations used to populate a UI, such as fetching a page of search results as structured data. It integrates easily with any protocol and comes out of the box with support for raw strings, images, and JSON. By providing built-in support for the features you need, Volley frees you from writing boilerplate code and allows you to concentrate on the logic that is specific to your app.

使用

Http请求

Step 1.创建RequestQueue队列

RequestQueue mQueue = Volley.newRequestQueue(this);

通过newRequestQueue创建一个新的RequestQueue队列。

Step 2.创建StringRequest对象

StringRequest stringRequest = new StringRequest(    "http://www.baidu.com",    new Response.Listener() {        @Override        public void onResponse(String response) {            Log.d("TAG", response);        }    }, new Response.ErrorListener() {        @Override        public void onErrorResponse(VolleyError error) {            Log.e("TAG", error.getMessage(), error);        }    });

这里可以看到StringRequest有三个默认参数,第一个是目标的Url,第二个是设置一个回调,第三个是监听错误回调的。

Step 3.将quest对象添加到队列里

mQueue.add(stringRequest);

最后就是将StringRequest对象往RequestQueue里面扔就行了。

图片请求

Step 1.创建RequestQueue对象

RequestQueue mQueue = Volley.newRequestQueue(this);

通过newRequestQueue创建一个新的RequestQueue队列。

Step 2.创建ImageRequest对象

mImageView = (ImageView) findViewById(R.id.imageView);ImageRequest imageRequest = new ImageRequest(    "http://app.sjk.ijinshan.com/market/img/zs/2300841/20150805140347461.png",    new Response.Listener() {        @Override        public void onResponse(Bitmap response) {            mImageView.setImageBitmap(response);        }    }, 0, 0,     Config.RGB_565, new Response.ErrorListener() {        @Override        public void onErrorResponse(VolleyError error) {            mImageView.setImageResource(R.drawable.default_image);        }    });

ImageRequest的构造函数接收六个参数,第一个参数就是图片的URL地址。第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片。

Step 3.将quest对象添加到队列里

mQueue.add(stringRequest);

最后就是将ImageRequest对象往RequestQueue里面扔就行了。

自定义Quest请求

自定义类

自定义的请求其实很简单,首先是继承父类Request,然后重载其中两个函数parseNetworkResponse(NetworkResponse response),deliverResponse(XmlPullParser response)。就可以像用StringResponse那样去使用了。

总结

Volley总体来说非常好用和方便,封装好了各种网络请求,特别是底层支持对开发者来说免除了很多烦恼,还可以定制自己的Response。

 

Android 浅析 Volley (二) 原理

前言

Linus Benedict Torvalds : RTFSC – Read The Funning Source Code

概括

本文通过对Volley源码进行分析来打通Volley的流程,并且知晓其原理,Volley的整体结构比较简单,但是细节有很多值得学习的地方。

Volley初始化

RequestQueue mQueue = Volley.newRequestQueue(this);

Volley的初始化就是简单的一行代码,但是里面做的事情比较复杂了。

Volley

这是Volley系统最主要的类之一,它用来初始化缓存目录和初始化下载响应队列。

Volley.newRequestQueue(…)

Creates a default instance of the worker pool and calls RequestQueue.start() on it.

HttpStack stack = new HurlStack();Network network = new BasicNetwork(stack);File cacheDir = new File(...);RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);queue.start();

这个函数不难,首先创建一个HttpStack对象和创建一个缓存文件,然后用创建的对象生成一个RequestQueue响应队列,最后调用RequestQueue.start()函数开始运行。

那么我们开始深入去看下,首先看下RequestQueue。

RequestQueue

A request dispatch queue with a thread pool of dispatchers.
Calling add(Request) will enqueue the given Request for dispatch, resolving from either cache or network on a worker thread, and then delivering a parsed response on the main thread.

RequestQueue.RequestQueue(…)

Creates the worker pool.
初始化这里有几个关键的点:
1、DEFAULT_NETWORK_THREAD_POOL_SIZE:访问网络的线程数,默认是4条线程。
2、new ExecutorDelivery(new Handler(Looper.getMainLooper())):新建一个用来推出网络响应和错误的类。
3、new NetworkDispatcher[threadPoolSize]:新建四条网络连接的线程。

 

//@param cache A Cache to use for persisting responses to disk//@param network A Network interface for performing HTTP requests//@param threadPoolSize Number of network dispatcher threads to create//@param delivery A ResponseDelivery interface for posting responses and errorsRequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery)

RequestQueue.Start()

Starts the dispatchers in this queue.

首先是创建一个CacheDispatcher缓存发送者,它是一个缓存发送的线程,然后调用CacheDispatcherstart()函数。
然后循环创建NetworkDispatcher对象,因为默认的线程数是4,所以会循环4次创建网络调度(和相应的线程)到池大小,接着再调用start()函数。
简单来说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。

RequestQueue.Stop()

Stops the cache and network dispatchers.

将所有缓存和网络发送者停止。

总结

通过这几行简单的函数就创建了Volley的缓存和网络发送者队列,为以后的请求建立了机制。

Volley添加请求

Volley的添加请求也很简单。

StringRequest stringRequest = new StringRequest(...);mQueue.add(stringRequest);

创建一个Request对象并且添加进Queue队列就行了。看起来简单,实际,好吧,很复杂。

RequestQueue

RequestQueue.add()

这里函数本身比较简单易懂,首先将Request标识为当前队列,然后添加到mCurrentRequests当前请求队列里。接着判断是否可以缓存,如果不行则直接调用网络队列进行请求。最后插入请求到现阶段,如果已经有一个缓存键的请求在进行。

总结

添加的操作是比较简单,但难的是里面的具体过程,缓存请求和网络请求都是独立线程,在添加到队列之后就会不断的去获取然后对网络或者缓存进行处理。

Volley 类分析

工具类

网络类

HttpStack

Performs an HTTP request with the given parameters.
用于处理 Http 请求,返回请求结果的接口。

HurlStack

based on HttpURLConnection.
实现 HttpStack 接口,基于HttpURLConnection进行各种请求方式的请求封装。

BasicNetwork

A network performing Volley requests over an HttpStack.
一个基于HttpStack执行Volley请求的网络。

调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
主要实现了以下功能:
1、利用 HttpStack 执行网络请求。
2、如果 Request 中带有实体信息,如 Etag,Last-Modify 等,则进行缓存新鲜度的验证,并处理 304(Not Modify)响应。
3、如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束。

Network

An interface for performing requests.
接口类,作为网络请求的主要接口,传入需要访问的执行信息,并且返回一个NetworkResponse网络响应对象。

缓存类

Cache

An interface for a cache keyed by a String with a byte array as data.
接口,一个可以获取请求结果,存储请求结果的缓存。

Entry get(String key)

通过 key 获取请求的缓存实体

void put(String key, Entry entry)

存入一个请求的缓存实体

void remove(String key)

移除指定的缓存实体

void clear()

清空缓存

Entry内部类

byte[] data : 请求返回的数据(Body 实体)
String etag Http : 响应首部中用于缓存新鲜度验证的 ETag
long serverDate Http : 响应首部中的响应产生时间
long ttl : 缓存的过期时间
long softTtl : 缓存的新鲜时间
Map responseHeaders : 响应的 Headers
boolean isExpired() : 判断缓存是否过期,过期缓存不能继续使用
boolean refreshNeeded() : 判断缓存是否新鲜,不新鲜的缓存需要发到服务端做新鲜度的检测

NoCache

什么缓存都没有。不做任何操作的缓存实现类,可将它作为构建RequestQueue的参数以实现一个不带缓存的请求队列。

DiskBasedCache

Cache implementation that caches files directly onto the hard disk in the specified directory. The default disk usage size is 5MB, but is configurable.

void initialize()

Initializes the DiskBasedCache by scanning for all files currently in the specified root directory. Creates the root directory if necessary.
初始化,扫描缓存目录得到所有缓存数据摘要信息放入内存。

Entry get(String key)

Returns the cache entry with the specified key if it exists, null otherwise.
从缓存中得到数据。先从缓存头中得到头部信息,然后读取缓存数据文件得到内容。

void put(String key, Entry entry)

Puts the entry with the specified key into the cache.
将数据文件内容保存到缓存。先检查缓存是否已满,已满则先删除缓存中部分数据,然后再新建缓存文件。

void pruneIfNeeded(int neededSpace)

Prunes the cache to fit the amount of bytes specified.
检查是否能再分配 neededSpace 字节的空间,如果不能则删除缓存中部分数据。

void clear()

Clears the cache. Deletes all cached files from disk.
清空缓存。

void remove(String key)

Removes the specified key from the cache if it exists.
删除缓存中某个元素。

CacheHeader

Handles holding onto the cache headers for an entry.
缓存文件头部信息在entry里。

ByteArrayPool

ByteArrayPool is a source and repository of byte[] objects.

byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。 主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。

PoolingByteArrayOutputStream

A variation of java.io.ByteArrayOutputStream that uses a pool of byte[] buffers instead of always allocating them fresh, saving on heap churn.

Authenticator

身份认证接口,用于基本认证或者摘要认证。这个类是 Volley 用于和身份验证打通的接口,比如 OAuth,不过目前的使用不是特别广泛和 Volley 的内部结合也不是特别紧密。

AndroidAuthenticator

继承 Authenticator,基于 Android AccountManager 的认证交互实现类。

基础类

NetworkResponse

Data and headers returned from performRequest(Request).
作为Network接口返回的值,Request的 parseNetworkResponse(…)参数,是 Volley 中用于内部 Response 转换的核心类。

封装了网络请求响应的 StatusCode,Headers 和 Body 等。

成员变量

int statusCode Http 响应状态码
byte[] data Body 数据
Map headers 响应 Headers
boolean notModified 表示是否为 304 响应
long networkTimeMs 请求耗时

内部 Response 转换流程图

CacheDispatcher

Provides a thread for performing cache triage on a queue of requests.

CacheDispatcher类是一个线程类,里面有四个比较重要的变量:
1、BlockingQueue> mCacheQueue来自缓存的队列。
2、BlockingQueue> mNetworkQueue将会访问网络的队列。
3、Cache mCache缓存的处理类。
4、ResponseDelivery mDelivery回调响应的类。

CacheDispatcher.run()

在线程被创建后马上就被执行了。里面首先会对缓存路径进行初始化工作。接着就进入一个无限的循环等待里。

首先会从缓存队列出取出请求,如果队列为空则会一直阻塞直到队列有数据,接着尝试从缓存当中取出响应结果,如何为空的话则把这条请求加入到网络请求队列中,如果不为空的话再判断该缓存是否已过期,如果已经过期了则同样把这条请求加入到网络请求队列中,否则就认为不需要重发网络请求,直接使用缓存中的数据即可。之后会调用Request的parseNetworkResponse()方法来对数据进行解析,最后就是将解析出来的数据进行回调了。

CacheDispatcher 流程图

NetworkDispatcher

Provides a thread for performing network dispatch from a queue of requests.

NetworkDispatcher类是一个线程类,里面有四个比较重要的变量:
1、BlockingQueue> mQueue响应来自服务的队列。
2、Network mNetwork 网络进度请求。
3、Cache mCache缓存的处理类。
4、ResponseDelivery mDelivery回调响应的类。

NetworkDispatcher.run()

在线程被创建后马上就被执行了。首先进入一个无限的循环等待里。等待任务进来。

在接受到请求后会直接访问网络发送请求,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。

NetworkDispatcher 流程图

ResponseDelivery

一个返回结果的分发接口。

有三个分发接口:
1、解析一个从网络或缓存的响应并分发。
postResponse(Request<?> request, Response<?> response);
2、解析一个从网络或缓存的响应并分发。提供的运行将会在分发后被执行。
postResponse(Request<?> request, Response<?> response, Runnable runnable);
3、推送一个收到的错误。
postError(Request<?> request, VolleyError error);

RetryPolicy

Retry policy for a request.

void retry(VolleyError error) throws VolleyError
确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。

DefaultRetryPolicy

Default retry policy for requests.

实现 RetryPolicy,Volley 默认的重试策略实现类。主要通过在 retry(…) 函数中判断重试次数是否达到上限确定是否继续重试。
其中mCurrentRetryCount变量表示已经重试次数。
mBackoffMultiplier表示每次重试之前的 timeout 该乘以的因子。
mCurrentTimeoutMs变量表示当前重试的 timeout 时间,会以mBackoffMultiplier作为因子累计前几次重试的 timeout。

更多相关文章

  1. Android(安卓)以Json格式发送Post服务请求
  2. Android(安卓)下拉刷新 ListRefresh 从网络加载图片
  3. android 网络请求框架
  4. 为Android封装的HTTP请求组件
  5. Android使用ccache减少编译时间
  6. 记一次新建Android工程报错: Could not download appcompat.aar (
  7. Android临时数据缓存方法
  8. RXJava与Retrofit联合使用
  9. Android中的几种网络请求方式详解

随机推荐

  1. 为什么使用PreparedStatement?
  2. 使用面向对象方法实现用户信息增删改查
  3. 在服务器上排除问题的头 5 分钟
  4. 初探MySQL Innodb集群
  5. 关于数据库的一些常识
  6. 数据库--存储过程详解
  7. 关键字--where与having的区别
  8. PHP基础:PHP抽象类和接口、类的重载和方法
  9. 每个开发人员应该知道的 10 个 Linux 命
  10. 40个常用Linux命令