Android Volley网络框架的基本使用

时间:2021-12-08 15:28:34

转载请标明出处:
http://blog.csdn.net/tyzlmjj/article/details/48973777
本文出自:【M家杰的博客】

[Android-Volley-GitHub]

Volley特点

  • 高效的Get/Post方式的数据请求交互
  • 对于频繁进行多次请求的处理比较好
  • 性能较为稳定

所需权限

<uses-permission android:name="android.permission.INTERNET"/> 

Volley框架的初始化

全局使用同一个类,可控性较高,也比较方便。
最好在Application中初始化(如下代码)

private static RequestQueue requestQueues;

@Override
public void onCreate() {
super.onCreate();
requestQueues = Volley.newRequestQueue(getApplicationContext());
}

public static RequestQueue getQueues() {
return requestQueues;
}

GET/POST请求的使用

请求类

  1. StringRequest
    StringRequest(请求模式,url地址, 请求成功的监听,请求出错的监听);
    最为常用的方法`,相对另外两种方法通用性比较高。

  2. JsonArrayRequest
    确定返回数据为JsonArray时使用可以提高一定的效率。

  3. JsonObjectRequest
    确定返回数据为JsonObject时使用可以提高一定的效率。

回调类

  • Response.ErrorListener()
    接收所有请求错误的返回,返回只有英文!

  • Response.Listener<T>
    接收所有请求成功的返回,返回值一般按方法来定,返回String、JsonObject、JsonArray等。

网络请求队列的建立

GET

String url = "http://news-at.zhihu.com/api/4/news/latest";
StringRequest request = new StringRequest(Method.GET, url,
new Listener<String>() {
@Override
public void onResponse(String arg0) {
//数据请求成功
Log.i("volley","GET返回:"+arg0);
}
}, new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError arg0) {
//数据请求失败
Log.i("volley",arg0.toString());
}
});
//加入TAG标签
request.setTag("main_get");
//添加到队列中
MyApplication.getQueues().add(request);

POST

String url = "";
StringRequest request = new StringRequest(Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String arg0) {
//数据请求成功
Log.i("volley", "POST返回:"+arg0);
}
},new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
//数据请求失败
Log.i("volley", arg0.toString());
}
}){
//Post在这个方法中写入要传递的参数
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String,String>();
params.put("LoginID","mjj");
params.put("Password","123456");
return params;
}
//这个方法中可以添加请求的头文件
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String,String> headers = new HashMap<String,String>();
headers.put("key", "value");
return headers;
}
};
//加入TAG标签
request.setTag("main_Post");
//添加到队列中
MyApplication.getQueues().add(request);

参数的传递

  • GET
    GET请求较为简单,要传递参数可以直接在url后面添加。
    例如 url = http://blog.csdn.net/tyzlmjj
    在后面添加参数之后变成:http://blog.csdn.net/tyzlmjj?ID=123&name=456
    表示传递2个参数ID和name,值分别为123和456

  • POST
    POST请求在传递参数时一般需要改写父类的getParams()方法。(上面的POST方法有给出示例)
    如果需要传递String类型的参数,可以改写getBody()。在源码中最终上传的数据还是从getBody()方法中取出,getParams()方法的存在只是为了更加方便,不需要写转换的代码。
    需要特别注意的是,JsonArrayRequest和JsonObjectRequest在传递参数方面存在一定的问题(也可能是本人没弄懂)所以建议在需要传递参数时不要使用这2个请求类,使用 StringRequest。

网络请求队列的取消

一般可以把请求的取消放在Activity的onStop()中(Fragment同理),这样可以在Activity销毁时同步关闭请求,实现与Activity生命周期的联动提高应用效率。一般按TAG来寻找比较方便。
cancelAll(tag)方法将取消所有tag值匹配的请求。

@Override
protected void onStop() {
super.onStop();
MyApplication.getQueues().cancelAll(TAG);
}

添加头文件

默认的Content-Type(内容类型)
JsonArrayRequest –> application/json
JsonObjectRequest –>application/json
StringRequest –> application/x-www-form-urlencoded
Request –> application/x-www-form-urlencoded

如果要修改默认的请求类型,可以改写getBodyContentType()方法。
如果需要在头文件中添加其他参数,可以改写getHeaders()方法。
虽然在写请求时改写也比较方便,但是头文件这种可能很多请求都不会变的情况下,建议自定义请求类,如下。

public class MyStringRequest extends StringRequest{
private Map<String, String> headers = new HashMap<String, String>();
private String contentType = "application/x-www-form-urlencoded";

public MyStringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, listener, errorListener);
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers;
}
@Override
public String getBodyContentType() {
return contentType;
}
public void setHeader(String title, String content) {
headers.put(title, content);
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}

超时和重新请求的设定

在Volley中,超时和重新请求需要我们实现RetryPolicy接口来配置参数,自己实现接口然后配置好像太麻烦了!幸好Volley为我们提供了一个默认的配置类DefaultRetryPolicy,它就是实现RetryPolicy接口完成的,我们直接拿来用就行了!
直接使用DefaultRetryPolicy配置很简单,如下。

StringRequest request = .........
//超时和重新请求配置
request.setRetryPolicy(new DefaultRetryPolicy(2500,0,1f));

从上面代码可以看出,DefaultRetryPolicy需要我们传入3个参数,
第一个参数(initialTimeoutMs)是超时时间
第二个参数(maxNumRetries)是最大重连次数
第三个参数(backoffMultiplier)是重新请求的系数
前2个参数很好理解,第三个参数一般没看过源码的就会产生一点疑问。
这里举个例子说明下。
假如这样配置:request.setRetryPolicy(new DefaultRetryPolicy(2500,2,2f));

第一次尝试请求:超时时间 = 2500(2.5秒)
2.5秒后第一次请求不知道什么原因超时了!
开始重新请求了
第二次尝试请求:超时时间 = 2500+ (2500* 2f)= 7500 (7.5秒)
7.5秒后第二次请求也不知道什么原因超时了!坑爹啊!
第三次尝试请求:超时时间 = 7500+ (7500* 2f)= 21500 (21.5秒)
21.5秒后!没有然后了 - -


异常的处理

在Volley中所有的异常都可以继承VolleyError类来分别处理,框架本身已经处理的很不错了,在失败监听中,可以通过Volley给出的类来区分不同异常,然后进行处理。

@Override
public void onErrorResponse(VolleyError error) {
if( error instanceof NetworkError) {
//网络异常
} else if( error instanceof ServerError) {
//服务器响应错误
} else if( error instanceof AuthFailureError) {
//请求时验证凭证失败
} else if( error instanceof ParseError) {
//解析服务器返回数据错误
} else if( error instanceof NoConnectionError) {
//网络请求无任何连接
} else if( error instanceof TimeoutError) {
//超时
}else{
//发生未知错误
}

}

设置优先级

Volley总共提供了4种请求的优先处理级别

public enum Priority {
LOW,//低
NORMAL,//正常(默认)
HIGH,//高
IMMEDIATE//立即
}

修改优先级可以通过改写getPriority()方法。


简单的封装

封装并不能提高代码的运行效率,在某种程度上我个人认为多次的封装很容易降低执行的效率。所以不推荐非常复杂的封装,简单的封装还是有很多可取之处的!封装可以更加个性化的去使用框架,按需求做封装可以避免经常性的重复敲代码,提高开发效率(好像说了一堆废话)
下面就Volley做一个简单的封装例子,主要是需要封装2个东东,一个回调的监听,一个使用的主方法。
在封装的时候,我让post请求默认采用StringRequest,而GET请求可以选择使用三种请求中的一种。主要是因为Volley自带的JsonArrayRequest和JsonObjectRequest在参数传递和数据解析方面存在一定问题和限制!

封装完之后的使用

private void doPost() {
String url = "";
Map<String,String> params = new HashMap<String,String>();
params.put("LoginID","mjj");
params.put("Password","123456");
VolleyRequest.doPost("main_post",url,params, listener);
}

VolleyListener<String> listener = new VolleyListener<String>() {
@Override
public void onRequestSuccess(String result) {
Log.i("volley", result);
}
@Override
public void onRequestError(VolleyError error) {
Log.i("volley", error.toString());
}
};

回调监听的封装

public abstract class VolleyListener<T> {
private Response.Listener<T> mListener;
private Response.ErrorListener mErrorListener;

public abstract void onRequestSuccess(T result);
public abstract void onRequestError(VolleyError error);

public Listener<T> successListener(){

mListener = new Listener<T>() {
@Override
public void onResponse(T arg0) {
onRequestSuccess(arg0);
}
};

return mListener;
}
public Response.ErrorListener errorListener() {
mErrorListener = new ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
onRequestError(arg0);
}
};
return mErrorListener;
}
}

主要类封装

public class VolleyRequest {

/** 默认超时时间 */
private static final int DEFAULT_TIMEOUT_MS = 5000;
/** 默认重新请求次数 */
private static final int DEFAULT_MAX_RETRIES = 0;
/** 默认重新请求的系数 */
private static final float DEFAULT_BACKOFF_MULT = 1f;

/** 请求方法 */
public enum RequestMethod {
STRING_REQUEST,
JSONOBJECT_REQUEST,
JSONARRAY_REQUEST
}

public static void doGet(RequestMethod requestMethod,String tag,String url,VolleyListener listener){

doRequest(requestMethod, Method.GET, tag, url, null, null, listener);

}

public static void doPost(String tag,String url,VolleyListener<String> listener){

doRequest(RequestMethod.STRING_REQUEST, Method.POST, tag, url, null, null, listener);

}

public static void doPost(String tag,String url,Map<String,String> map,VolleyListener<String> listener){

doRequest(RequestMethod.STRING_REQUEST, Method.POST, tag, url, null, map, listener);

}

public static void doPost(String tag,String url,String params,VolleyListener<String> listener){

doRequest(RequestMethod.STRING_REQUEST, Method.POST, tag, url, params, null, listener);

}

private static void doRequest(RequestMethod requestMethod,int method,String tag,String url,@Nullable String params,@Nullable Map<String,String> map,VolleyListener listener){

MyApplication.getQueues().cancelAll(tag);

Request request = null;
switch (requestMethod) {
case STRING_REQUEST:
request = doStringRequest(method, url, params, map, listener);
break;
case JSONOBJECT_REQUEST:
request = doJsonObjectRequest(method, url, listener);
break;
case JSONARRAY_REQUEST:
request = doJsonArrayRequest(method, url, listener);
break;
}

if (request != null) {

request.setRetryPolicy(new DefaultRetryPolicy(DEFAULT_TIMEOUT_MS,DEFAULT_MAX_RETRIES,DEFAULT_BACKOFF_MULT));
request.setTag(tag);

MyApplication.getQueues().add(request);
}

}

private static Request<String> doStringRequest(int method,String url,@Nullable final String params,@Nullable final Map<String,String> map,VolleyListener<String> listener){

StringRequest request =
new StringRequest(method, url,listener.successListener(),listener.errorListener())
{

@Override
protected Map<String, String> getParams() throws AuthFailureError {

if(map != null){
return map;
}
return super.getParams();
}

@Override
public byte[] getBody() throws AuthFailureError {

if (params != null) {
return params.getBytes();
}
return super.getBody();
}
};

return request;
}

private static Request<JSONObject> doJsonObjectRequest(int method,String url,VolleyListener<JSONObject> listener){

JsonObjectRequest request =
new JsonObjectRequest(method, url,listener.successListener(),listener.errorListener());

return request;
}

private static Request<JSONArray> doJsonArrayRequest(int method,String url,VolleyListener<JSONArray> listener){

JsonArrayRequest request =
new JsonArrayRequest(method, url,listener.successListener(),listener.errorListener());

return request;
}

}

自定义请求类

有时为了开发方便,volley提供的三个请求类都无法很好的满足我们的需求,那么我们可以继承Volley的Request类,自定义一个请求类来使用。
下面给出一个使用[GSON]解析JSON数据的请求类例子:

public class GsonRequest<T> extends Request<T> {  

private final Listener<T> mListener;

private Gson mGson;

private Class<T> mClass;

public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
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);
}
}

加载网络图片

图片加载的话Volley的功能并不是很全面,下面只做一个简单的例子。
推荐一个加载图片的框架:[Universal Image Loader]

String url = "http://pic1.zhimg.com/742dda03170770a6d0854f0ece09692c.jpg";
ImageRequest request = new ImageRequest(url, new Listener<Bitmap>() {
@Override
public void onResponse(Bitmap arg0) {
ImageView.setImageBitmap(arg0);
}
}, 0, 0,ScaleType.CENTER,Config.RGB_565, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {

}
});
MyApplication.getQueues().add(request);