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

转载请注明出处: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>() {

					@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
			protected 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>() {

					@Override
					public void onResponse(JSONObject jsonObject) {
						T t = JSON.parseObject(jsonObject.toString(), 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();

			}

		};
		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>() {

					@Override
					public void onResponse(T t) {
						listener.onSuccess(t);
					}
				}, new ErrorListener() {

					@Override
					public 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
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值