本文主要用代码给出如何对volley进行封装制定出自己的request,实现项目工程中自己的网络请求框架,主要参考的是郭大神的博客http://blog.csdn.net/guolin_blog/article/details/17612763
首先给出自定义的Request类:
public class MyVolleyRequest<T> extends Request<T> {
private Gson mGson;
private Class<T> mClass;
private final Response.Listener<T> mListener;
private RequestParams parameters;
private String command;
private String mRequestBody;
private static final String PROTOCOL_CHARSET = "utf-8";
private static final String PROTOCOL_CONTENT_TYPE =String.format("application/json; charset=%s", PROTOCOL_CHARSET);
public MyVolleyRequest(int method, Class<T> clazz, String url,RequestParams requestParams, final MyRequestListener<T> listener) {
super(method, UrlConfig.SERVICE_URL, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.onFailure(error);
}
});
mGson=new Gson();
mClass=clazz;
parameters=requestParams;
command=url;
generateParams();
mListener=new Response.Listener<T>() {
@Override
public void onResponse(T response) {
listener.onSuccess(response);
}
};
}
public MyVolleyRequest(Class<T> clazz,String url,RequestParams requestParams,MyRequestListener<T> listener){
this(Method.POST,clazz,url,requestParams,listener);
}
private void generateParams() {
Map<String, Object> paramsMap = new HashMap<String, Object>();
paramsMap.put("command", command);
paramsMap.put("param", parameters.getUrlParams());
mRequestBody = mGson.toJson(paramsMap);
}
@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
public String getBodyContentType() {
return PROTOCOL_CONTENT_TYPE;
}
@Override
public byte[] getBody() throws AuthFailureError {
try {
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}
该自定义request类与郭大神给出的demo区别是新加入了传递参数到服务器的方法,以及合并回调接口,改变传递参数等变化。该类有两个构造方法,第二个是重载的构造方法,调用第一个构造方法,传递了post方法参数,以及url,传递的参数以及回调接口。在第一个构造函数里面通过UrlConfig.SERVICE_URL向父类传递url地址,而构造方法里面的url其实是总体url的一部分,主要是用来区分不同的服务器接口,这样服务器端组合出来的url才是一个请求的真正完全地址。接着通过generateParams方法获取要提交给服务器的参数,然后通过重写getBody方法将参数设置进去。parseNetworkResponse方法用来解析服务器返回的数据,通过deliverResponse方法分发出去,最后在mListener.onResponse(response)的接口里面回调,从而实现一次网络请求处理。
配合该类的实现,需要定义一个接口类如下:
public interface MyRequestListener<T> {之所以要写一个这个接口类,就是为了把Response的Listener和ErrorListener两个接口合并一下,省得还要在传递参数的时候写两个。
public void onSuccess(T response);
public void onFailure(VolleyError error);
}
还需要一个参数类
public class RequestParams {
protected final static String LOG_TAG = "RequestParams";
protected final ConcurrentHashMap<String, Object> urlParams = new ConcurrentHashMap<String, Object>();
public RequestParams() {
this((Map<String, Object>) null);
}
public RequestParams(Map<String, Object> source) {
if (source != null) {
for (Map.Entry<String, Object> entry : source.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
}
public void put(String key, String value) {
if (key != null && value != null) {
// 防止注入攻击过滤掉特殊字符
value = value.replace("<", "").replace(">", "").replace("'", "")
.replace("/", "").replace("%", "");
urlParams.put(key, value);
}
}
public void put(String key, Object value) {
if (value != null)
urlParams.put(key, value);
}
public void put(String key, int value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
public void put(String key, long value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
public void put(String key, double value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (ConcurrentHashMap.Entry<String, Object> entry : urlParams
.entrySet()) {
if (result.length() > 0)
result.append("&");
result.append(entry.getKey());
result.append("=");
result.append(entry.getValue());
}
return result.toString();
}
public ConcurrentHashMap<String, Object> getUrlParams() {
return urlParams;
}
}
接着封装一个公共类
public class HttpUtil {公共类里面主要是调用的时候建立好自己的request的时候,设置一下请求参数,然后加入请求队列即可,请求队列最好是要在全局的application里面获取,自定义的application如下:
private static final String TAG="httpUtil";
public static Request jsonRequest(Class<?> clazz, String url, RequestParams requestParams, MyRequestListener<?> listener){
MyVolleyRequest volleyRequest=new MyVolleyRequest(clazz,url,requestParams,listener);
volleyRequest.setShouldCache(false);
volleyRequest.setRetryPolicy(new DefaultRetryPolicy(300000,//默认超时时间,应设置一个稍微大点儿的
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默认最大尝试次数
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
return AppContext.getInstance().getmRequestQueue().add(volleyRequest);
}
public static void showErrorToast(Context ctx, VolleyError error) {
String msg = "";
if (error instanceof TimeoutError) {
msg = "操作超时!";
} else if (error instanceof ServerError) {
msg = "服务器异常!";
} else if (error instanceof NoConnectionError) {
msg = "无法连接到洗洗服务器!";
} else if (error instanceof NetworkError) {
msg = "网络异常!";
} else {
msg = "操作失败!";
}
ApplicationUtil.showToast(ctx,msg);
Log.d(TAG, error.getMessage() + "");
}
}
public class AppContext extends Application {这样使用自定义的application时要在manifest里面加上android:name=".application.AppContext"才行。
private static AppContext Instance;
private RequestQueue mRequestQueue;
@Override
public void onCreate() {
super.onCreate();
Instance=this;
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
public static AppContext getInstance(){
return AppContext.Instance;
}
public RequestQueue getmRequestQueue(){
return mRequestQueue;
}
}
最后使用代码如下:
RequestParams requestLogin = new RequestParams();
requestLogin.put("account", "admin");
requestLogin.put("password", "123456");
HttpUtil.jsonRequest(SimpleResponse.class, "10001000",requestLogin,new MyRequestListener<SimpleResponse>() {
@Override
public void onSuccess(SimpleResponse response) {
String str=response.toString();
}
@Override
public void onFailure(VolleyError error) {
Log.d("tag",error.toString()+"");
}
});
这里定义一个SimpleResponse类来解析结果就好了,一开始封装的MyVolleyRequest类里面在具体应用中还可以优化,比如在代码
mListener=new Response.Listener<T>() {
@Override
public void onResponse(T response) {
listener.onSuccess(response);
}
};
里面从总体上进行条件筛选,可以在解析结果的时候先不要组装成具体的类,把jsonString先分发出去,然后定义一个基本解析类,然后在上面的回调方法里面先使用基本解析类解析结果进行初期判断,这样会省去在每一个回调方法里面进行重复判断。基础解析过后再用具体的类解析回调到每一个请求接口里面就好了。当然还有很多其他方法可以进行封装和优化,大家可以一起探讨。