上篇文章中咱们对 HttpUrlConnection 的相关用法稍做介绍,能够看到若是不对它进行封装,那么每次使用时就必须写不少重复的代码,而且须要本身建立线程进行网络链接,获取到响应结果后还须要切换回主线程来更新 UI。这样的过程已经足够麻烦,若是在获取网络图片或者进行文件下载的场景时,更是须要借助 AsyncTask 等进行实现,这样繁杂的步骤显然是不利于开发的。php
Google 在 2013 年的 IO 大会上针对 Android 中缺乏一个功能强大、体验良好的网络加载类这个问题,推出了咱们今天介绍的主角——Volley。Volley 框架能够说是将AsyncHttpClient、Universal-Image-Loader 等第三方网络加载框架和图片加载框架的优势集于一身。既将网络加载功能封装的很是简单,又可以实现很是复杂的网络加载任务,好比图片压缩和缓存。Volley 的含义翻译过来是万箭齐发,它很是适合于处理那些数据量不大但通讯极为频繁的网络请求任务,但在涉及通讯数据量很大的任务中(如文件下载),Volley 的表现就要差不少。下图是 IO 大会上介绍 Volley 时配图:html
Volley 并不在 Android SDK 中,因此若是要使用 Volley 就必须在项目中导入 Volley 这个库。Volley 没有官方的Maven repository 或者 Jcenter repository,因此必须依赖于 Volley 的源代码。android
在项目中导入 Volley 主要有这样几种方式:git
1. 下载 volley 的源码并将其做为项目的一个 module。github
在 Android Studio 中咱们能够将第三方的代码做为咱们项目工程的一个 module。这个作法是最合适的,不只能够直接在 IDE 中查看 Volley 的源码,还能够在源码基础是上进行修改。api
第一步,下载 Volley 源码,使用 Git 能够轻松实现这一步:缓存
git clone https://github.com/google/volley.git复制代码
第二步:在 Android Studio 中选择「File」→「New」→「Import Module」,而后选择下载好的 Volley 文件夹。这样就导入了 Volley 的源码做为咱们项目中的一个 module。bash
第三步:选择「File」→「Project Structure」,将 Volley module 做为咱们 app module 的依赖。服务器
通过上述三步,就能够顺利地在咱们本身的代码中使用 Volley 的功能了。网络
2. 在依赖列表中添加以下一段依赖:
compile 'com.mcxiaoke.volley:library-aar:1.0.15'复制代码
这是官方 repository 的一个镜像,最简单直接,但不被官方所支持。
3. 将打包好的 jar 文件添加到项目 libs 目录下。
点击这里下载 CSDN 上打包好的 jar 文件。
在项目中成功导入 Volley 后,下面咱们就来进入正题,学习一下 Volley 的相关用法。Volley 的整体设计思路是基于一个 RequestQueue(请求队列),开发者只须要建立适合应用场景的 Request,并将其添加到 RequestQueue 便可实现网络请求。
结合这个设计思路,咱们很快就能够提取出 Volley 通用的使用步骤:
首先来看看 StringRequest 的使用。它是 Request 的一个子类,顾名思义这个 Request 会返回一段字符串类型的响应数据。
咱们按照上述的三个步骤来进行说明。
建立 RequestQueue 对象
使用 Volley.newRequestQueue() 方法建立 RequestQueue 对象,传入当前的上下文(Context)。
RequestQueue mQueue = Volley.newRequestQueue(this);复制代码
RequestQueue 能够缓存全部的 Http 请求,而且适合高并发的网络请求,因此不须要为每一个 Http 请求都建立一个 RequestQueue 对象,一般在一个 Activity 中建立一个全局的 RequestQueue 对象,甚至若是你的应用程序网络功能不多时,整个应用中只需有一个 RequestQueue 对象便可(对应 Application)。
建立 StringRequest 对象
接下来须要咱们指定具体请求的内容,因此咱们新建一个 StringRequest 对象,如如下代码所示:
//获取控件
TextView tvCode = (TextView) findViewById(R.id.string_code);
//请求的 URL 地址
String url = "http://lixiaoyu.cc";
//建立 StringRequest 对象
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
tvCode.setText(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
tvCode.setText("出错了");
}
});复制代码
StringRequest 共有两个构造方法,一个有 3 个参数,用于默认以 GET 方式发送网络请求,这 3 个参数分别是:
String url:请求的网址
Listener< String> listener:响应成功的回调函数
ErrorListener errorListener:响应失败的回调函数
例如上面代码中,网址为个人我的博客网站的 URL,响应成功时直接将该页面的 HTML 代码显示在 TextView 中,响应失败则在 TextView 显示一段错误提示。(上述两个回调函数都是直接在主线程中执行,因此不须要咱们本身去切换线程,太方便了)
若是须要使用 POST 方法向网页提交数据,就须要使用 4 个参数的构造方法。参数分别为:
int method:网络请求方式,取值能够是 Request.Method.POST,Request.Method.HEAD 等
String url
Listener listener
ErrorListener errorListener
后 3 个参数与上面都是一致的。使用 POST 时,咱们须要将数据发送给服务器,Volley 并无设计在构造方法中加入相似 Params 这种参数,可是 Volley 在处理 POST 请求时,会调用 StringRequest 的父类 Request 的 getParams() 方法,咱们能够在这个方法中加入想要提交到服务器的数据。如如下代码所示:
//获取控件
TextView tvCode = (TextView) findViewById(R.id.string_code);
//请求的 URL 地址
String url = "http://ip.taobao.com/service/getIpInfo.php";
StringRequest request = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
tvCode.setText(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
tvCode.setText("出错了");
}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<>();
map.put("ip","192.168.0.188");
return map;
}
};复制代码
在代码中,首先指定构造方法的第一个参数为 POST,而后其余参数的设置与以前一致。覆盖父类中的 getParams() 方法,经过 Map 构造想要提交的数据,最后返回给 Request。
将 StringRequest 对象添加到 RequestQueue 中
最后一步就是将 Request 对象添加到 RequestQueue 中,RequestQueue 就能自动处理这个请求,并将相应结果发送到请求的回调函数中。如如下代码所示:
mQueue.add(request);复制代码
网络请求的相应结果一般是 XML 格式和 Json 格式,在 Android 开发中不少时候都是 Json 格式。Volley 中定义了 JsonRequest 来方便、快速地实现响应结果为 Json 的网络请求。JsonRequest 是一个抽象类,有两个子类,JsonObjectRequest 和 JsonArrayRequest,返回结果分别是 JsonObject 对象和 JsonArray 对象。
JsonRequest 的使用方式和 StringRequest 有着高度的一致性,咱们以 JsonObjectRequest 为例(JsonArrayRequest 用法彻底同样):
/**
* 1.建立全局的 RequestQueue,为了显示方便写在一块了
*/
mQueue = Volley.newRequestQueue(this);
/**
* 2.建立 JsonObjectRequest 对象,设置 URL,这里使用了 Gank 的 API 接口
* 和请求一块儿 POST 到服务器的 JsonObject 对象,这里设置为 null,
* 响应成功或失败的回调函数
*/
String url = "http://gank.io/api/random/data/Android/2";
JsonObjectRequest request = new JsonObjectRequest(url, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.i("TAG", "onResponse: " + response.toString());
try {
boolean isError = response.getBoolean("error");
if (!isError) {
JSONArray results = response.getJSONArray("results");
JSONObject index = results.getJSONObject(0);
String title = index.getString("desc");
tvJson.setText(title);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
tvJson.setText("出错了");
}
});
/**
* 3.将 JsonObjectRequest 对象添加到 RequestQueue 中
*/
mQueue.add(request);复制代码
经过上面的代码能够看到,使用步骤是彻底一致的,只是在响应成功时回调函数的泛型从 String 类型变成了 JsonObject 类型,咱们在这个回调函数中就能够对获取到的 Json 数据进行处理,提取出想要的信息。
Volley 的另外一个强大功能就体如今可以很是方便地进行网络图片的加载,而且可以对图片进行压缩、缓存等处理,不用担忧图片过大时所致使的内存泄漏等问题。
使用 Volley 来加载网络图片主要有三种方式,一是使用 ImageRequest,二是使用 ImageLoader,三是使用 NetworkImageView 这个自定义控件。下面依次来介绍一下。
使用 ImageRequest
因为加载网络图片也是很是常见的网络请求之一,因此 Volley 中也封装了专门用于图片加载的 ImageRequest,它一样是 Request 的子类,因此使用方法和上述的 StringRequest、JsonRequest 如出一辙。示例代码以下:
ImageView imageView = (ImageView) findViewById(R.id.image_img);
RequestQueue queue = Volley.newRequestQueue(this);
String imgUrl = "http://image.wufazhuce.com/FiBzmwDotMhGiJjSuqi1Lg5h_Zjm";
ImageRequest request = new ImageRequest(imgUrl, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
imageView.setImageResource(R.mipmap.ic_launcher);
}
});
queue.add(request);复制代码
若是加载图片成功就设置给 ImageView,若是加载失败就在 ImageView 上显示一张默认的图片。ImageRequest 使用时须要注意其构造方法,它有两个构造方法,一个有 6 个参数,一个有 7 个参数,直接看看最全参数列表:
String url:须要加载的图片地址
Response.Listener< Bitmap> listener:响应成功的回调,好比设置给 ImageView
int maxWidth:图片的最大宽度
int maxHeight:图片的最大高度,若是图片的实际宽高超过设置的最大宽高值,会对图片进行压缩,以指定大小进行显示,最大宽高均设置为 0 表示不进行任何压缩。
ScaleType scaleType:图片的缩放方式,这个参数能够省略,默认是以总体向中心缩放的方式
Config decodeConfig:图片 Bitmap 的编码方式,值为 Bitmap.Config 类中的常量,有 RGB_565, ARGB_8888等值。
Response.ErrorListener errorListener:响应失败的回调,好比给 ImageView 设置一张默认显示的图片
实际运行效果以下:
使用 ImageLoader
ImageLoader 内部一样是用 ImageRequest 实现的,而且可以在此基础上实现图片的缓存,还能够过滤掉重复的连接,避免重复发送请求,比 ImageRequest 更加高效。
ImageLoader 的用法就和前面提到的 Request 子类的用法有所不一样。步骤主要有:
1. 建立一个 RequestQueue 对象。这步与上述一致,不用多说。
RequestQueue mQueue = Volley.newRequestQueue(this);复制代码
2. 建立一个 ImageLoader 对象。传入 RequestQueue 对象和 ImageCache 对象做为参数,这里先建立一个空的 ImageCache 实例。
ImageLoader loader = new ImageLoader(queue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});复制代码
3. 获取一个 ImageListener 对象。使用 ImageLoader 的 getImageListener() 方法能够获取到 ImageListener 对象,在参数中设置须要加载图片的 ImageView,默认图片和加载失败显示的图片。
ImageView imageView = (ImageView) findViewById(R.id.image_img);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView,
R.mipmap.ic_launcher,R.mipmap.ic_launcher_round);复制代码
loader.get(imgUrl, listener,200,200);复制代码
实际运行效果如图所示,和 ImageRequest 不一样, ImageLoader 会先在 ImageView 上显示设置的默认图片,等图片加载成功后进行替换,若加载失败则显示设置的失败图片。
咱们这里虽然实现了与 ImageRequest 相同效果的功能,可是并无将 ImageLoader 的优点发挥出来,由于咱们在建立 ImageLoader 时第二个参数是 ImageCache 的一个空实现。咱们应该在这里对图片进行缓存处理。
如下这段代码来自郭神的 Volley 文章,演示了使用 LruCache 来缓存图片,避免重复加载和内存泄漏。
public class BitmapCache implements ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
int maxSize = 10 * 1024 * 1024;
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());复制代码
使用 NetworkImageView
NetworkImageView 是 Volley 中的一个自定义控件,继承自 ImageView,拥有 ImageView 的所有功能,而且实现了加载网络图片的功能。它的用法也能够大体分为以下几步:
1. 建立一个 RequestQueue 对象。
2. 建立一个 ImageLoader 对象。
以上两步就不用多说了,和 ImageLoader 中是同样的。
RequestQueue mQueue = Volley.newRequestQueue(this);
ImageLoader loader = new ImageLoader(queue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});复制代码
3. 在布局文件中申明 NetworkImageView 控件。
<com.android.volley.toolbox.NetworkImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:id="@+id/networkiv"/>复制代码
4. 在 Activity 中对控件进行实例化。同时能够进行一些自定义的设置。
ImageView imageView = (NetworkImageView) findViewById(R.id.networkiv);
imageView.setDefaultImageResId(R.mipmap.ic_launcher);
imageView.setErrorImageResId(R.mipmap.ic_launcher_round);复制代码
这里咱们一样设置了默认显示的图片和加载失败时显示的图片。
5. 调用NetworkImageView的setImageUrl() 方法加载图片。将网络图片地址和 ImageLoader 对象传入便可。
String imgUrl = "http://image.wufazhuce.com/FiBzmwDotMhGiJjSuqi1Lg5h_Zjm";
imageView.setImageUrl(imgUrl, loader);复制代码
这里有一个须要注意的地方是,在 ImageRequest 和 ImageLoader 中,咱们均可以指定图片的最大宽高,而在 NetworkImageView 中,并无相应的实现。这是由于 NetworkImageView 是一个控件,在申明控件时就会进行宽高的设置,NetworkImageView 会将加载的图片宽高和控件宽高进行比较,若是超过就会进行压缩,若是控件的宽高都指定为 wrap_content,则不会压缩。
这篇文章中比较详细地介绍了 Volley 的来历和基础的用法,包括获取普通的字符串数据和 Json 格式的数据,以及如何使用 Volley 加载网络图片。在有关图片缓存的部分,由于不了解 LruCache 的有关内容,因此引用了部分其余人的代码,以做示例。
谢谢,下篇文章见。
郭霖:初识Volley的基本用法
blog.csdn.net/guolin_blog…
郭霖:使用Volley加载网络图片
blog.csdn.net/guolin_blog…
刘望舒:Volley 用法全解析
liuwangshu.cn/application…
泡在网上的日子:Android 网络通讯框架Volley简介
www.jcodecraeer.com/a/anzhuokai…
泡在网上的日子:网络请求库Volley详解
www.jcodecraeer.com/a/anzhuokai…