Volley网络框架完全解析(使用篇)
在Android中,网络请求无非就这两种:HttpURLConnection和HttpClient( Apache),我们在使用时一般都会对它们进行一系列的封装,但是这过程不免有些繁琐,所以,Google官方也考虑到了这点,在2013年Google I/O大会上就推出了一个新的网络请求框架——Volley,它将各种网络请求都简单化,并且把AsyncHttpClient和Universal-Image-Loader两大框架的优点集一身,Volley用在数据量不大的网络请求操作时它的性能表现的非常出色,但是Volley如果在进行数据量大的网络操作时(下载文件等),那么Volley将表现的比较糟糕。
关于Volley的架构可以看看这个文章Volley架构
Volley有这么几大功能:
1、普通数据、JSON、图片的异步加载
2、网络请求优先级处理
3、自带硬盘缓存(普通数据、图片、JSON),另外我们在加载图片时候通过ImageLoader还可加入LruCache
4、取消请求
5、与Activity生命周期联动(Activity退出时同时取消所有的请求)
可见,Volley框架是非常强大的,下面我就一一介绍怎么使用Volley框架。
Volley框架的原理:它内部是通过一个请求队列(RequestQueue)来维护所有请求,我们新创建一个请求(request)后通过RequestQueue.add()方法将请求添加置请求队列中,然后调用RequestQueue.start()方法执行请求队列中的方法
Volley中包含这么几种类型的请求:
- StringRequest - 返回字符串数据
- JsonObjectRequest - 返回JSONArray数据
- JsonArrayRequest - 返回JSONObject数据
- ImageRequest - 返回Bitmap类型数据
当然使用前我们必须导入Volley.jar包(可以去网上下载),或者通过git下载
git clone https://android.googlesource.com/platform/frameworks/volley
这里给出我上传的jar包下载地址:Volley.jar
创建RequestQueue请求队列
RequestQueue是通过Volley的静态方法newRequestQueue来创建的:
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
一般我们会继承自Application在自定义的MyApplication中创建一个全局的请求队列,用来维护app中的网络请求。
StringRequest
这里主要讲最常用的GET和POST请求方式:
这里我用聚合网上查询手机号码归属地的数据为例子,我们创建一个StringRequest请求,然后给该请求设置一个Tag,用来标记这个请求,取消请求时候我们可以通过这个Tag来取消某个或者所有请求,再把该请求加入请求队列,最后执行请求队列中的请求。
StringRequest的构造方法为:
/**
* @method 请求方式(GET、POST等)
* @url 请求url
* @listener 请求成功回调的接口
* @errorListener 请求失败回调的接口
*/
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener)
GET
一个完整的StringRequest的GET请求如下:
String url = "http://apis.juhe.cn/mobile/get?phone=18270837821&key=9a4329bdf84fa69d193ce601c22b949d";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());//创建一个请求队列
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(),volleyError.toString(),Toast.LENGTH_SHORT).show();
}
});
request.setTag("zxy");
mRequestQueue.add(request);
mRequestQueue.start();
POST
一个完整的StringRequest的POST请求如下:
String url = "http://apis.juhe.cn/mobile/get";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(),volleyError.toString(),Toast.LENGTH_SHORT).show();
}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map =new HashMap<>();
map.put("phone","18270837821");
map.put("key","9a4329bdf84fa69d193ce601c22b949d");
return map;
}
};
request.setTag("zxy");
mRequestQueue.add(request);
mRequestQueue.start();
其中,因为是以POST方式请求数据的,所以我们必须实现StringRequest的getParams()方法,该方法返回的是Map<String, String>类型的集合,也就是用<key,value>的形式把数据通过POST传入服务器
JsonObjectRequest
JsonObjectRequest构造方法为:
/**
* @method 请求方式(GET、POST等)
* @url 请求url
* @jsonRequest 请求传入的json数据
* @listener 请求成功回调的接口
* @errorListener 请求失败回调的接口
*/
public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener)
GET
一个完整的JsonObjectRequest的GET请求如下:
因为用的是GET请求方式,参数是在url中传入,所以JSONObject对象传入null
String url = "http://apis.juhe.cn/mobile/get?phone=18270837821&key=9a4329bdf84fa69d193ce601c22b949d";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Toast.makeText(getApplicationContext(),jsonObject.toString(),Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(),volleyError.toString(),Toast.LENGTH_SHORT).show();
}
});
request.setTag("zxy");
mRequestQueue.add(request);
mRequestQueue.start();
POST
一个完整的JsonObjectRequest的POST请求如下:
String url = "http://apis.juhe.cn/mobile/get";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("phone", "18270837821");
jsonObject.put("key", "9a4329bdf84fa69d193ce601c22b949d");
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Toast.makeText(getApplicationContext(),jsonObject.toString(),Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(),volleyError.toString(),Toast.LENGTH_SHORT).show();
}
});
request.setTag("zxy");
mRequestQueue.add(request);
mRequestQueue.start();
用以上StringRequest和JSONObjectRequest请求我们都获取到了数据,如图
虽然这两种方式都可以返回我们请求的数据,但是JSONObjectRequest请求在处理json对象的返回结果时候效率更高,所以确定返回结果是json类型时候可以使用JSONObjectRequest
ImageRequest
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)
普通的加载方式(ImageView显示)
一个标准的普通请求网络图片的方法:
String url="http://img.my.csdn.net/uploads/201507/21/1437459520_6685.jpg";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(),volleyError.toString(),Toast.LENGTH_SHORT).show();
}
});
request.setTag("zxy");
mRequestQueue.add(request);
mRequestQueue.start();
}
这种方式只适合在图片数量不多的情况下使用,否则则需要考虑使用下面两种,同样,因为Volley内部本身就有硬盘缓存机制,在没网的情况下则会加载缓存中的图片
带LruCache缓存的加载方式(ImageView+ImageLoader+ImageCache)
我们上一种方法就是使用Volley中的ImageRequest请求的加载网络图片,这种方法没有LruCache和显示效果不好,下面我们来使用Volley中的ImageLoader+ImageCache的加载方式,这种方式可以在网络差的情况下和加载出错的情况下给出一个默认的提示图片,而且使用了LruCache缓存可以避免OOM。
首先我们创建一个ImageLoader对象,ImageLoader构造方法
public ImageLoader(RequestQueue queue, ImageLoader.ImageCache imageCache)
需要传入请求队列对象和ImageCache对象,我们再来看看ImageCache对象
public interface ImageCache{...}
发现它是ImageLoader内部的一个接口,所以我们得实现这个接口然后传入,于是我们创建一个BimapCache实现ImageCache接口:
public class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> mBitmapLruCache;
public BitmapCache() {
int maxCache = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxCache / 8;
mBitmapLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount();
}
};
}
@Override
public Bitmap getBitmap(String key) {
return mBitmapLruCache.get(key);
}
@Override
public void putBitmap(String key, Bitmap bitmap) {
mBitmapLruCache.put(key, bitmap);
}
}
其实这就是创建一个图片内存缓存对象。
之后我们再使用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.getImageListener()来得到,我们来看看它的参数:
/**
* @view - 表示将图片设置到哪个控件对象上
* @defaultImageResId- 默认时显示的图片的资源id
* @errorImageResId- 加载出错时显示的图片的资源id
*/
public static ImageLoader.ImageListener getImageListener(final ImageView view, final int defaultImageResId, final int errorImageResId)
好了一切都好办了,一个带LruCache缓存的加载图片的标准请求:
String url="http://img.my.csdn.net/uploads/201507/21/1437459520_6685.jpg";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
ImageLoader mImageLoader = new ImageLoader(mRequestQueue,new BitmapCache());
ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(mImageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
mImageLoader.get(url,imageListener,0,0);
效果图:
【注意】:mImageLoader.get(url,imageListener)加载图片的原理是什么呢?其实从源码中很容易看出,它首先会得到url对应的key,然后判断硬盘缓存中是否含有该key的图片,如果有则取出,没有则通过网络请求重新加载图片,所以使用这种双缓存的方式加载网络图片,可以有效的防止OOM
使用NetworkImageView+ImageLoader+ImageCache
Volley框架中对图片的请求做的特别好,其中还为我们提供了一个专门用于显示图片的控件:NetworkImageView,该控件继承自ImageView,除了拥有ImageView控件的功能之外,还多了三个方法:
public void setImageUrl(String url, ImageLoader imageLoader) {
this.mUrl = url;
this.mImageLoader = imageLoader;
this.loadImageIfNecessary(false);
}
public void setDefaultImageResId(int defaultImage) {
this.mDefaultImageId = defaultImage;
}
public void setErrorImageResId(int errorImage) {
this.mErrorImageId = errorImage;
}
- setDefaultImageResId - 设置该控件默认时显示的图片
- setErrorImageResId - 设置加载网络图片失败时显示的图片
- setImageUrl - 从网络上加载图片
使用NetworkImageView需要在layout中替换掉ImageView:
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/net_img"
android:layout_width="match_parent"
android:layout_height="match_parent" />
同样这里也需要使用ImageLoader和ImageCache,一个标准使用NetworkImageView的例子为:
String url="http://img.my.csdn.net/uploads/201507/21/1437459520_6685.jpg";
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
ImageLoader mImageLoader = new ImageLoader(mRequestQueue,new BitmapCache());
mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher);//设置默认显示的图片
mNetworkImageView.setErrorImageResId(R.mipmap.ic_launcher);//设置加载出错时显示的图片
mNetworkImageView.setImageUrl(url,mImageLoader);
效果为:
可以看到用NetworkImageView和第二种方式效果是一样的,它同样会先检查硬盘缓存中有没有该图片,如果没有,再通过网络加载得到该图片,如果有则直接设置。既然和第二种一样,那为什么还推出NetworkImageView这个控件呢?答案就是NetworkImageView这个控件在你的Activity退出时候会自动取消网络请求,即完全不需要我们担心网络请求生命周期的问题。
【注意】:在上述两种使用了LruCache缓存加载图片的方法,当图片量较大时推荐使用,否则当你只有几张图片则使用第一种比较好,因为你使用LruCache时需要为它分配一定的内存空间,而图片量不大时候也使用LruCache缓存,那这块空间则一直是作为缓存图片用的,占着这块内存空间,相反反而会得不偿失。
Volley与Activity生命周期联动与取消请求
其实就是在Activity退出时候或销毁时候,取消对应的网络请求,避免网络请求在后台浪费资源,所以,我们一般在onStop()方法中通过之前设置的Tag取消网络请求:
@Override
protected void onStop() {
super.onStop();
mRequestQueue.cancelAll("zxy");
}
RequestQueue.cancelAll()方法会过滤出Tag为“zxy”的所有请求都一并取消。
或者通过Request.cancel()取消请求,把当前Activity的请求放入一个List集合中,关闭Activity时分别取消。
好了,这篇Volley框架的使用篇已经讲完了,下一篇讲Volley的缓存!!!
Volley网络框架完全解析(使用篇)的更多相关文章
- Volley网络框架完全解析(缓存篇)
在上一篇中讲完了Volley框架怎么使用,那么这篇就来讲讲Volley框架的缓存机制 我们看Volley内部源码发现: Volley框架内部自己处理了DiskBasedCache硬盘缓存,但是没有处理 ...
- Volley网络框架完全解析(实战篇)
好了,今天就通过一个瀑布流demo,来使用Volley框架请求网络图片. 前言: 我们使用NetworkImageView显示图片: 1.因为该控件可以自动的管理好请求的生命周期,当与父控件detac ...
- 谷歌Volley网络框架讲解——BasicNetwork类
谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...
- 谷歌Volley网络框架讲解——第一篇
自从公司新招了几个android工程师后,我清闲了些许.于是就可以有时间写写博客,研究一些没来的研究的东西. 今年的谷歌IO大会上,谷歌推出了自己的网络框架——Volley.不久前就听说了但是没有cl ...
- Volley网络框架的使用
Volley的特点: 使用网络通信更快.更简单 Get/Post网络请求网络图像的高效率异步请求 可以对网络请求的优先级进行排序处理 可以进行网络请求的缓存 可以取消多级别请求 可以和Activi ...
- 谷歌Volley网络框架讲解——HttpStack及其实现类
前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类.我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpStack有两个实现类. 其中Htt ...
- 谷歌Volley网络框架讲解——网络枢纽
研究了这么久的Volley,愈来愈发现这个框架的精美和人性化.比起民间一些框架强很多,一开始总是盲人摸象找不到头绪,现在终于有些明朗了.Volley其实就是一个请求队列的代理类,我们看下UML. 这就 ...
- 谷歌Volley网络框架讲解——Network及其实现类
我们看到Network接口只有一个实现类BasicNetwork,而HttpStack有两个实现类. BasicNetwork这个类是toolbox工具箱包里的,实现了Network接口. 先来看下N ...
- Android网络框架Volley(体验篇)
Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp ...
随机推荐
- AleNet模型笔记
谁创造了AlexNet? AlexNet是有Hinton大神的弟子Alex Krizhevsky提出的深度卷积神经网络.它可视为LeNet的更深更宽的版本. AlexNet主要用到的技术 成功使用Re ...
- 120. Triangle(中等)
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...
- Java 读取Excel文件
https://www.cnblogs.com/wwzyy/p/5962076.html 先把上面的参考博客看了,如果会导入包的话,下面的教程就直接忽略emm 这时候,你应该把jar包下载 ...
- Docker如何获取镜像
可以使用 docker pull 命令来从仓库获取所需要的镜像. 下面的例子将从 Docker Hub 仓库下载一个 Ubuntu 12.04 操作系统的镜像. $ sudo docker pull ...
- Java常用集合学习总结
一 数组 数组可以存储基本数据类型和对象的一种容器,长度固定,所以不适合在对象数量未知的情况下使用. Arrays : 用于操作数组对象的工具类,里面都是静态方法. Arrays.asList:把A ...
- 我为什么放弃使用MyBatis3的Mapper注解
最近在使用MyBatis3做项目.在使用注解实现Mapper的时候遇到了比较奇葩的问题:在实现数据的batch insert的时候总是报错.好不容易可以正常插入了,但是又不能返回自增的主键id到实体b ...
- 20160208.CCPP体系详解(0018天)
程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针详解: ...
- Kafka系列之-Kafka入门
接下来的这些博客,主要内容来自<Learning Apache Kafka Second Edition>这本书,书不厚,200多页.接下来摘录出本书中的重要知识点,偶尔参考一些网络资料, ...
- Cocoa层粒子发射器动画添加多个cell的一种重构
在iOS动画之旅第19章中最后的挑战中需要我们在雪花例子发生器中添加多个雪花贴图,也就是多个cell,因为我们不可能将每个cell的参数都重新写一遍,所以有必要写一个helper方法来做这件事: fu ...
- 4-sum问题
给定一个整数数组,判断能否从中找出4个数a.b.c.d,使得他们的和为0,如果能,请找出所有满足和为0个4个数对. #define SIZE 10 void judgeAndPut(int* arr, ...