引言:对于网络请求这块来说最早接触是
AsyncHttpClient
后来又简单接触了xUtils
再后来就是OkHttp
了,官方的Volley
只是听说过,并没有真正使用过。时间:2016年12月03日00:18:35
作者:JustDo23
GitHub:https://github.com/mcxiaoke/android-volley
01. 简介
在慕课网上找了相关视频Android-Volley详解
Volley
是 Google 在2013年推出的 Android 平台的网络通信库。Volley
特点,快捷,简单,网络图像,高效异步处理请求排序,缓存,多级别取消,和 Activity 生命周期联动;缺点是不适合进行文件的上传下载。
Volley
的请求同样是包含有get
和post
请求;同时根据返回结果的不同可以挑选使用StringRequest
或JsonObjectRequest
或JsonArrayRequest
;请求回调有Success
或Error
等回调;全局建立一个请求队列
,方便网络请求的添加
和取消
;使用tag
标签方便查找请求,并管理请求的取消,和 Activity 进行联动使用。
建议:在这里强调一下,不论使用的是什么网络请求框,都应该自己进行一下二次封装,方便同一管理。
02. 入门代码
在Gradle
文件中导入依赖
compile 'com.android.volley:volley:1.0.0'
新建Application
并实例化请求队列
public class JustApplication extends Application {
private static RequestQueue requestQueue;// 全局的请求队列
@Override
public void onCreate() {
super.onCreate();
requestQueue = Volley.newRequestQueue(this);// 实例化请求队列
}
public static RequestQueue getRequestQueue() {
return requestQueue;
}
}
在 Activity 中进行网络请求
private void doStringGet() {
String url = "https://www.baidu.com";// 参数:[请求方式][请求链接][成功回调][失败回调]
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener() {
@Override
public void onResponse(String response) {
LogUtil.e(response);// 这个是成功的回调
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
LogUtil.e(error.toString());// 这个是失败的回调
}
});
stringRequest.setTag("doVolleyGet");// 设置标签
JustApplication.getRequestQueue().add(stringRequest);// 将请求添加进队列
}
使用POST
方式进行网络请求,和GET
方式不同的是需要将参数进行封装
private void doStringPost() {
String url = "https://www.baidu.com";// 参数:[请求方式][请求链接][成功回调][失败回调]
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, null, null) {// 重写父类的方法,返回网络请求的参数
@Override
protected Map getParams() throws AuthFailureError {
Map params = new HashMap<>();
params.put("phone", "15812345678");
params.put("key", "abcdefghigklmn");
return params;
}
};
stringRequest.setTag("doStringPost");// 设置标签
JustApplication.getRequestQueue().add(stringRequest);// 将请求添加进队列
}
另外使用JsonObjectRequest
进行网络请求和StringRequest
也有些区别,就是不用重写返回参数,而是将一个JsonObject
对象的参数直接进行传递。
private void doJsonPost() {
String url = "https://www.baidu.com";
Map params = new HashMap<>();
params.put("phone", "15812345678");
params.put("key", "abcdefghigklmn");
JSONObject jsonObject = new JSONObject(params);// 将 Map 转为 JsonObject 的参数
// 参数:[请求方式][请求链接][请求参数][成功回调][失败回调]
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
LogUtil.e(response.toString());// 这个是成功的回调
}
}, null);
jsonObjectRequest.setTag("doJsonPost");// 设置标签
JustApplication.getRequestQueue().add(jsonObjectRequest);// 将请求添加进队列
}
在现有代码的基础上,给界面添加一个 TextView 并在 Volley 网络请求的回调中直接将返回的数据设置给 TextView ,测试发现回调
可以直接
操作UI
。
03. 加载网络图片
方式一:直接请求图片 URL 并将图片进行显示
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// 参数:[图片Url][成功回调][图片最大宽度][图片最大高度][填充方式][位图配置][失败回调]
ImageRequest imageRequest = new ImageRequest(imageUrl, new Response.Listener() {
@Override
public void onResponse(Bitmap response) {
iv_show.setImageBitmap(response);// 请求成功返回 Bitmap 方便使用
}// [图片最大宽度][图片最大高度]给0表示原图显示,否则会进行压缩
}, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
iv_show.setImageResource(R.mipmap.ic_launcher);// 请求失败的回调
}
});
imageRequest.setTag("getNetImage");// 设置标签
JustApplication.getRequestQueue().add(imageRequest);// 添加进队列
}
方式二:使用 ImageLoader 配合 ImageCache 及 ImageListener 进行图片显示
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// [获取一个 ImageLoader 对象] 参数:[请求队列][图片缓存对象]
ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
// [获取一个 ImageListener 对象] 参数:[ ImageView ][默认显示图片][加载失败显示图片]
ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(iv_show, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
// [使用 ImageLoader 加载图片] 参数:[图片Url][图片加载监听][图片最大宽度][图片最大高度][填充方式]
imageLoader.get(imageUrl, imageListener, 0, 0, ImageView.ScaleType.CENTER_CROP);
}
进行图片缓存的类
/**
* 图片缓存
*
* @author JustDo23
*/
public class BitmapCache implements ImageLoader.ImageCache {
private LruCache cache;// 缓存图片
private int maxSize = 10 * 1024 * 1024;// 最大10MB
/**
* 构造方法中实例化
*/
public BitmapCache() {
cache = new LruCache(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
/**
* 获取图片
*
* @param url 图片 URL
* @return 图片 Bitmap
*/
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
/**
* 缓存图片
*
* @param url 图片 URL
* @return 图片 Bitmap
*/
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
方式二:使用 Volley 内部封装的显示网络图片控件 NetworkImageView
niv_show = (NetworkImageView) findViewById(R.id.niv_show);
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// [获取一个 ImageLoader 对象] 参数:[请求队列][图片缓存对象]
ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
// [设置默认显示图片]
niv_show.setDefaultImageResId(R.mipmap.ic_launcher);
// [设置加载失败显示图片]
niv_show.setErrorImageResId(R.mipmap.ic_launcher);
// [设置 URL 和 ImageLoader]
niv_show.setImageUrl(imageUrl, imageLoader);
}
04. 自定义 Request
Android Volley完全解析(三),定制自己的Request
当 Volley 本身提供的请求不够用的时候,可以参考 Volley 中请求的实现方式来进行自定义。其中Request
带泛型的请求基类。看下StringRequest
的源码
/**
* A canned request for retrieving the response body at a given URL as a String.
*/
public class StringRequest extends Request {
private final Listener mListener;
/**
* Creates a new request with the given method.
*
* @param method the request {@link Method} to use
* @param url URL to fetch the string at
* @param listener Listener to receive the String response
* @param errorListener Error listener, or null to ignore errors
*/
public StringRequest(int method, String url, Listener listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
/**
* Creates a new GET request.
*
* @param url URL to fetch the string at
* @param listener Listener to receive the String response
* @param errorListener Error listener, or null to ignore errors
*/
public StringRequest(String url, Listener listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}
再此基础上,编写自定义的 Request
/**
* 带有 XML 解析的网络请求
*
* @author JustDo23
*/
public class XMLRequest extends Request {
private final Response.Listener mListener;// 网络请求成功的回调
/**
* [必须有一个][构造方法]
*
* @param method 请求方式
* @param url 请求的网络地址
* @param listener 成功的回调
* @param errorListener 失败的回调
*/
public XMLRequest(int method, String url, Response.Listener listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
/**
* 默认的 GET 请求
*/
public XMLRequest(String url, Response.Listener listener, Response.ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
/**
* [必须重写][网络请求返回数据]
*
* @param response 网络请求结果
* @return 处理之后的数据
*/
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
try {// 先获取网络返回是字符串再将字符串转成流传递给解析器最后将解析器返回
String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlString));
return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (XmlPullParserException e) {
return Response.error(new ParseError(e));
}
}
/**
* [必须重写][将parseNetworkResponse方法返回的数据返回给主线程]
*
* @param response
*/
@Override
protected void deliverResponse(XmlPullParser response) {
mListener.onResponse(response);
}
}
再利用 Gson 进行封装
/**
* 带有 Gson 解析的网络请求
*
* @author JustDo23
*/
public class GsonRequest extends Request {
private final Response.Listener mListener;// 网络请求成功的回调
private Gson mGson;// Gson 对象
private Class mClass;// 解析后 JavaBean
public GsonRequest(int method, String url, Class clazz, Response.Listener listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class clazz, Response.Listener listener, Response.ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
try {// 先获取网络请求返回的Json字符串,再利用Gson将字符串转成对象
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}
05. 再度深入
Android Volley完全解析(四),带你从源码的角度理解Volley
全局维护一个队列,根据手机版本的不同使用不用的HttpStack
当然也可以扩展到使用OKHttp
,首次初始化5个网络请求线程,先初始化一个带缓存的网络请求线程,再初始化四个不带缓存的网络请求线程。默认情况下,每条网络请求都是可以进行缓存的。获取到缓存之后,还会判断缓存是否已经过期,过期则重新进行网络请求否则直接使用缓存。
06. Https
Android 网络--我是怎么做的: Volley+OkHttp+Https
利用 Volley 实现 Https 在网上大概就几种方式:直接信任所有,跳过验证,拓展到 OKHttp 添加证书等等。这篇文章是在网络上找的比较好的一篇。
使用自签名的证书进行操作,就会遇到这些比较复杂麻烦的问题,例如访问12306网站
。一般只要是使用CA
证书认证的网站,默认都是信任的,直接就能进行访问的,比如https:www.baidu.com
在 Volley 中同样可以直接访问不要考虑认证的问题。由于iOS
年底提交项目必须使用https
所以接口面临证书之类的问题,宝宝真是好害怕,一切都准备就绪后,不料买了个CA 证书
,结果问题简单化。
证书操作
01. 将 CER 证书转成 BKS
参考:http://blog.csdn.net/u010314594/article/details/50765534
工具: [ JCE Provider ] bcprov-jdk15on-155.jar http://www.bouncycastle.org/latest_releases.html 在网站下载到最新版。
命令:下载之后需要使用命令行进行操作,这个命令比较多,而且不能有回车。
keytool -importcert -v -trustcacerts -alias 位置1
-file 位置2
-keystore 位置3 -storetype BKS
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider
-providerpath 位置4
-storepass 位置5
解释:
位置1:是个随便取的别名,供keytool方便管理
位置2:cer或crt证书的全地址
位置3:生成后bks文件的位置,建议写全地址
位置4:上面下载JCE Provider包的位置
位置5:生成后证书的密码,自己设置,需要在项目中使用,用于确保KeyStore文件本身安全
命令执行之后,如果失败会有报错提示,使用最新版本基本没有问题。命令执行成功,最后会有中文[是|否]的选择,输入[是]即可完成全部过程。命名要符号 Java 命名规范。
// 个人操作命令
keytool -importcert -v -trustcacerts -alias test12306 -file /Users/just/Desktop/test12306/srca.cer -keystore /Users/just/Desktop/test12306/test12306.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /Users/just/Desktop/test12306/bcprov-jdk15on-155.jar -storepass test12306
02. 提取 CER 证书字符串
命令:
keytool -printcert -rfc -file xxx.cer
命令行操作,证书文件路径可全路径,可在证书所在目录执行。
Demo 地址
下载