Volley封装,一行代码搞定http请求(重点介绍cookie、https、自定义requst请求)

来源:互联网 发布:淘宝购物车营销在哪 编辑:程序博客网 时间:2024/06/05 12:43

转载请注明出处:http://blog.csdn.net/ganklun/article/details/43372355

Google 于 2013 I/O上,发布了Volley。Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮。Volley适合数据量不大但是通信频繁的场景。本篇文章将主要介绍volley的基本用法,以及经过封装修改后,实现一行代码搞定StringRequst、JsonObjectRequest、自定义Request的http请求,同时将介绍Volley如何对Cookie以及https的支持。下面就由本屌一步一步带大家领略volley的风采吧。

1、初始化Volley队列

 首先,我们需要创建一个volley队列,也就是一个RequestQueue对象。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。这里我们使用单例模式,由于本屌比较懒,所以当然使用懒汉模型啦,O(∩_∩)O哈哈~开个玩笑。代码如下所示:

private static RequestQueue getInstance(Context context) {if (requestQueue == null) {synchronized (VolleyUtil.class) {//这里的VolleyUtil.class就是我们封装好后的类。if (requestQueue == null) {requestQueue = Volley.newRequestQueue(context);requestQueue.start();}}}return requestQueue;}

2、添加Request请求对象到队列

事实上,这是第三个步骤了。实际情况是先产生request对象,然后将其加入队列。代码如下所示:

private static <T> void addRequest(RequestQueue requestQueue,Request<T> request, Object tag) {if (tag != null) {request.setTag(tag);}request.setShouldCache(false);request.setRetryPolicy(new DefaultRetryPolicy(TIME_OUT,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));requestQueue.add(request);}

上面方法第一个参数就是我们第一步中产生的RequestQueue队列,第二个参数就是接下来我们将要介绍的各种Request对象,第三个参数则是每一个Request

对象的标识,这个标识有什么作用,大家别急,过会也会提到。该方法就做了四件事,第一设置标识,第二设置是否缓存,第三设置超时情况,第四将Request

对象添加到RequestQueue队列。

3、实例化Request对象

一、StringRequest

由于传参方式的不同,这里会将StringRequest对象的情况分为POST与GET两种情况。先看POST,代码如下所示:


public static <T> void sendStringRequestByPost(Context context, String url,Object tag, final Map<String, String> params, final Class<T> clazz,final HttpBackListener<T> listener, final boolean isLogin,final String cookieValue) {StringRequest stringRequest = new StringRequest(Method.POST, url,new Response.Listener<String>() {@Overridepublic void onResponse(String s) {T t = JSON.parseObject(s, clazz);listener.onSuccess(t);}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError volleyError) {if (volleyError != null) {Log.e("VolleyError", volleyError.getMessage());listener.onFail(volleyError.networkResponse.statusCode);}}}) {@Overridepublic Map<String, String> getHeaders() throws AuthFailureError {Map<String, String> headers = new HashMap<String, String>();if (!isLogin) {headers.put(GlobConstant.COOKIE,cookieValue);return headers;}return super.getHeaders();}@Overrideprotected Map<String, String> getParams() throws AuthFailureError {return params == null ? super.getParams() : params;}};addRequest(getInstance(context), stringRequest, tag);}

该方法第一个参数不多说应用上下文,第二个参数就是你请求的httpUrl地址,第三个参数就是该request对象的tag标识,第四个参数就是我们需要提供的键值对参数,这里

是个Map<String,String>类型,第五个参数就是我们自定义的model类(解析完获取json后需要转化的实体类),第六个参数则是我们自定义的接口回调,用于处理调用成功

或者失败的情形,第七个参数其实是应用层面的参数,因为Android应用通常是在登录的时候去获取最新的header里的Cookie值,登录后为了维持与后台的会话连接,

需将最新的cookie值添加到请求头里,故重写getHeaders()方法,大家也可以根据自己的需要重写该方法。第八个参数就是我们添加的cookie值。接下来我们关注下重写

的getParams()方法,经过本屌测试该方法对于GET请求并不能讲参数顺利地提交到后台,POST请求没有问题,特此说明下,大家也可以去验证下是不是这样,欢迎前来

拍砖,(*^__^*) 嘻嘻……


接下来直接看GET请求的情况,代码如下所示:

public static <T> void sendStringRequestByGet(Context context,            final String url, Object tag, final Map<String, String> params,            final Class<T> clazz, final HttpBackListener<T> listener,            final boolean isLogin, final String cookieValue) {        StringRequest stringRequest = new StringRequest(Method.GET, url,                new Response.Listener<String>() {                    @Override                    public void onResponse(String s) {                        T t = JSON.parseObject(s, clazz);                        listener.onSuccess(t);                    }                }, new Response.ErrorListener() {                    @Override                    public void onErrorResponse(VolleyError volleyError) {                        if (volleyError != null) {                            Log.e("VolleyError", volleyError.getMessage());                            listener.onFail(volleyError.networkResponse.statusCode);                        }                    }                }) {            @Override            public Map<String, String> getHeaders() throws AuthFailureError {                Map<String, String> headers = new HashMap<String, String>();                if (!isLogin) {                    headers.put(GlobConstant.COOKIE,                            cookieValue);                    return headers;                }                return super.getHeaders();            }            @Override            public String getUrl() {                String sParams = BaseUtil.mapToStringParams(params);                if (sParams.equals("")) {                    return super.getUrl();                } else {                    return url + "?" + sParams;                }            }        };        addRequest(getInstance(context), stringRequest, tag);    }

上面方法与POST的情况并没有太大区别,不同的是我们不再以重写getParams()的方式提交Map<String,String>键值对参数,而是重写getUrl()方法将params转化成paramKey1=paramValue1&paramKey2=paramValue2...的形式。

二、JsonObjectRequest

JsonObjectRequest,顾名思义传递json咯, 直接上代码:

public static <T> void sendJsonObject(Context context, int method,String url, JSONObject jsonRequest, Object tag,final Class<T> clazz, final HttpBackListener<T> listener,final boolean isLogin, final String cookieValue) {JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(method,url, jsonRequest, new Response.Listener<JSONObject>() {@Overridepublic void onResponse(JSONObject jsonObject) {T t = JSON.parseObject(jsonObject.toString(), clazz);listener.onSuccess(t);}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError volleyError) {if (volleyError != null) {Log.e("VolleyError", volleyError.getMessage());listener.onFail(volleyError.networkResponse.statusCode);}}}) {@Overridepublic Map<String, String> getHeaders() throws AuthFailureError {Map<String, String> headers = new HashMap<String, String>();if (!isLogin) {headers.put(GlobConstant.COOKIE,cookieValue);return headers;}return super.getHeaders();}};addRequest(getInstance(context), jsonObjectRequest, tag);}

这里我们需要传递JsonObject对象格式的参数,响应后public void onResponse(JSONObject jsonObject)得到的也是一个JsonObject对象,该类型就是Android自带的org.json包下的。

三、自定义Request

这里依然是传递json的情况,与上面JsonObjectRequest不同的是,这里我们重写Request,事实上,在volley里Request是所有类型的Request的最顶层父类,包括上面介绍的StringRequest,JsonObjectRequest。所以不难想象,我们自定义Request也难逃其中,自定义一个JsonRequest 去继承 Request类。代码如下:

public class JsonRequest<T> extends Request<T> {    private static final String PROTOCOL_CHARSET      = "utf-8";    private static final String PROTOCOL_CONTENT_TYPE = String.format("application/json; charset=%s", PROTOCOL_CHARSET);    private String              jsonStr;    private Class<T>            clazz;    private boolean             isLogin;    private Listener<T>         listener;    private String cookieValue;    public JsonRequest(int method, String url, String jsonStr, Class<T> clazz, boolean isLogin, String cookieValue, Listener<T> listener,            ErrorListener errorListener) {        super(method, url, errorListener);        this.jsonStr = jsonStr;        this.clazz = clazz;        this.isLogin = isLogin;        this.cookieValue = cookieValue;        this.listener = listener;    }    @Override    public Map<String, String> getHeaders() throws AuthFailureError {        Map<String, String> headers = new HashMap<String, String>();        if (!isLogin) {            headers.put(GlobConstant.COOKIE,cookieValue);            return headers;        }        return super.getHeaders();    }    @Override    protected void deliverResponse(T t) {        listener.onResponse(t);    }    @Override    public String getBodyContentType() {        return PROTOCOL_CONTENT_TYPE;    }    @Override    public byte[] getBody() throws AuthFailureError {        return jsonStr == null ? super.getBody() : jsonStr.getBytes();    }    @Override    protected Response<T> parseNetworkResponse(NetworkResponse response) {        try {            if (isLogin) {            //解析请求返回的响应头                Header[] headers = response.apacheHeaders;                if (headers != null) {                    for (Header header : headers) {                        if (header.getName().equalsIgnoreCase(GlobConstant.SET_COOKIE)) {                           //这里大家可以自由发挥,去解析自己需要的cookie.                        }                    }                }            }            String json = new String(response.data, PROTOCOL_CHARSET);            return Response.success(JSON.parseObject(json, clazz), HttpHeaderParser.parseCacheHeaders(response));        } catch (UnsupportedEncodingException e) {            return Response.error(new ParseError(e));        }    }}

首先,我们重写getBodyContentType()方法来说明我们传递的媒体类型,是application/json,字符编码是UTF-8,然后我们重写了getBody()方法,注意上面的jsonStr即将你自定义的Model类(比如User类)用fastJson或者Gson转成的json字符串。然后我们重点关注 parseNetworkResponse(NetworkResponse response)这个方法,这里可以通过response.apacheHeaders获取所有的响应头,然后根据自己的需要去解析相应的cookie。最后利用Json解析工具类将Json串映射成我们自定义的实体类T。这里我用的是fastJson。至于请求头的处理和之前的情况一样,这里不再赘述。自定义好了request后,发送原理就和上面的一样了,代码如下:

public static <T> void sendJsonRequest(Context context, int method,String url, String jsonStr, Object tag, Class<T> clazz,final HttpBackListener<T> listener, final boolean isLogin,final String cookieValue) {JsonRequest<T> jsonRequest = new JsonRequest<T>(method, url, jsonStr,clazz, isLogin, cookieValue, new Listener<T>() {@Overridepublic void onResponse(T t) {listener.onSuccess(t);}}, new ErrorListener() {@Overridepublic void onErrorResponse(VolleyError volleyError) {if (volleyError != null) {Log.e("VolleyError", volleyError.getMessage());listener.onFail(volleyError.networkResponse.statusCode);}}});addRequest(getInstance(context), jsonRequest, tag);}

是不是和上面的情况很像呀,对,其实就是这样,这里我们调用我们自定义的Request。

4、取消Request请求

Activity被终止之后,如果继续使用其中的Context,除了没必要的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们要防止这种情况的发生。

使用volley,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。代码如下:

public static void cancelAllByTag(Object tag) {if (null != requestQueue) {if (tag != null) {requestQueue.cancelAll(tag);}}}public static void cancelAll(Context context) {if (null != requestQueue) {requestQueue.cancelAll(context);}}


你可以在Activity的onStop方法里调用以上两个方法。Volley里所有的请求结果会返回给主线程,如果在主线程里取消了某些请求,则这些请求将不会被返回给主线程。

5、支持https

对于https的支持,大家可以参考这篇文章http://blog.csdn.net/llwdslal/article/details/18052723。本屌已经将其方法编译到最新的jar包里,大家无须编写任何代码。直接使用即可。

6、代码下载

https://github.com/GankLun/VolleyUtils。

7、总结

Volley在性能方面进行了大幅度的调整,它的适用场景就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。本来还想写一点关于volley网络图片加载的东东,说了本人比较懒,第一次写这样的技术博客,哎。。。还是留到下一次写吧。最后,大家是不是可以考虑在今后的网络程序编写中引入volley了呢?


1 0
原创粉丝点击