Android Volley网络框架的基本使用


转载请标明出处:
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
    接收所有请求成功的返回,返回值一般按方法来定,返回String、JsonObject、JsonArray等。

网络请求队列的建立

GET

String url = "http://news-at.zhihu.com/api/4/news/latest";
StringRequest request = new StringRequest(Method.GET, url, 
        new Listener() {
            @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 headers = new HashMap();
    private String contentType = "application/x-www-form-urlencoded";

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

    @Override
    public Map 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 {
    private Response.Listener mListener;
    private Response.ErrorListener mErrorListener;

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

    public Listener successListener(){

        mListener = new Listener() {
            @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 listener){

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

    }

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

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

    }

    public static void doPost(String tag,String url,String params,VolleyListener 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 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 doStringRequest(int method,String url,@Nullable final String params,@Nullable final Map map,VolleyListener listener){

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

            @Override
            protected Map 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 doJsonObjectRequest(int method,String url,VolleyListener listener){

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

        return request;
    }

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

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

        return request;
    }

}

自定义请求类

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

public class GsonRequest extends Request {  

    private final Listener mListener;  

    private Gson mGson;  

    private Class mClass;  

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

你可能感兴趣的:(android框架使用)