我们已经讲了ImageRequest、StringRequest等等的用法 今天我就来自定义一个Request 我们可以让我们的请求返回泛型的数据、然后我们根据需要去解析相应的数据
好 首先我们先来看一下 StringR equest的源码
-
- public class StringRequest extends Request<String> {
- private final Listener<String> mListener;
- /**
- * Creates a new request with the given method.
- *
- * @param method the request {@link Method} to use
- * @param url URL to fetch the string at
- * @param listener Listener to receive the String response
- * @param errorListener Error listener, or null to ignore errors
- */
- public StringRequest(int method, String url, Listener<String> listener,
- ErrorListener errorListener) {
- super(method, url, errorListener);
- mListener = listener;
- }
- /**
- * Creates a new GET request.
- *
- * @param url URL to fetch the string at
- * @param listener Listener to receive the String response
- * @param errorListener Error listener, or null to ignore errors
- */
- public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
- this(Method.GET, url, listener, errorListener);
- }
- @Override
- protected void deliverResponse(String response) {
- mListener.onResponse(response);
- }
- @Override
- protected Response<String> parseNetworkResponse(NetworkResponse response) {
- String parsed;
- try {
- parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
- } catch (UnsupportedEncodingException e) {
- parsed = new String(response.data);
- }
- return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
- }
- }
我们看到这个源码很简单 首先我们的StringRequest继承了Request 这里的 Request我们可以指定泛型的 我们在这里指定的是String类型的 接下来我们看到两个带有参数的构造方法 在构造函数中一定要调用Super() 讲一些参数传给父类 因为请求、相应都是在父类中自动进行的
接下来的两个方法parseNetworkResponse deliverResponse 因为这两个方法在Request中都是抽象的 我们必须实现这两个方法 deliverResponse 这个方法很简单 只是调用了 mListener.onResponse(response); 这样我们就可以将服务器返回的数据进行回调了 parseNetworkResponse是对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的data变量中的,这里将数据取出然后组装成一个String,并传入Response的success()方法中即可 HttpHeaderParser.parseCharset(response.headers)其实就是获取我们的返回流的编码,也就是我上面服务器设置的utf-8 好了 这样我们就把StringRequest的源码看完了 是不是感觉很简单 接下来我们就自定义一个Request
我们知道谷歌官方推出了Gson 咱们就用这个Gson解析咱们服务器返回的数据 然后咱们自定义一个GsonRequest 看代码
/*
* 自定义Request 请求服务器 (Volley框架)T的类型是bean 这个地方解析数据的时候使用Gson
*/
public class GsonRequest<T> extends Request<T> {
/** Charset for request. */
private static final String PROTOCOL_CHARSET = "utf-8";
/** Content type for request. */
private static final String PROTOCOL_CONTENT_TYPE = String.format(
"application/json; charset=%s", PROTOCOL_CHARSET);
/* 解析方式 */
private Gson mGson;
// 上下文
private Context context;
// 监听器
private Listener<T> mListener;
// 泛型类(解析的Bean类型)
private Class<T> mClass;
// 上传的参数
private String mRequestBody;
/**
* params(参数)
*/
private Map<String, String> params = new HashMap<String, String>();
/**
* headers(头)
*/
private Map<String, String> headers = new HashMap<String, String>();
/**
* timeOut(设置超时时间 )
*/
private int timeOut = 35000;
public GsonRequest(int method, String url, String mRequestBody,
Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mRequestBody = mRequestBody;
this.mListener = listener;
}
/**
* 初始化的类型
*/
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
}
/**
* 初始化的类型带Param
*/
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener,
Map<String, String> params) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
this.params = params;
}
// 设置超时
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(timeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
@Override
public String getBodyContentType() {
// TODO Auto-generated method stub
return PROTOCOL_CONTENT_TYPE;
}
// 添加header
private void setHeaders(String key, String value) {
headers.put(key, value);
}
// 设置超时时间
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
@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
public Map<String, String> getHeaders() throws AuthFailureError {
// TODO Auto-generated method stub
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
@Override
protected void deliverResponse(T t) {
mListener.onResponse(t);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
// 得到服务器返回的数据
String strObject = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
// 转化为泛型的对象
T parsedGSON = mGson.fromJson(strObject, mClass);
return Response.success(parsedGSON,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
Log.e("error", e.getMessage().toString());
return Response.error(new ParseError(e));
}
}
这个是我做项目的时候写的 里面的方法不一定都要实现 根据自己的实际情况去写 接下来引用网上的一段代码看一下简单的写法
- 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);
- }
- }
有人会问那我们怎么进行请求呢 好 我们直接上代码
// 请求服务器
public <T> void requestGet(int requestType, String urlStr, final int tag,
Map<String, Object> map, Class<T> cls) {
GsonRequest<T> mRequest = new GsonRequest<T>(requestType, returnGetUrl(
urlStr, map), cls, new Listener<T>() {
@Override
public void onResponse(T t) {
responseInterface.successResponse(t, tag);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
responseInterface.errorResonse(arg0.getMessage(), tag);
}
});
mRequest.setTag(tag);
BaseApplication.getRequestQueuemanager().add(mRequest);
}
我们看有五个参数第一个是请求方式是get还是post第二个是URL 第三个是tag 这个参数待会我们回调的时候会判断是返回的哪个实体类或者实体类的集合
第四个参数是我们传入的参数 我当时用的Get 所有需要把参数拼接到URL后面 所以我们看到returnGetUrl这个方法就是我用来拼接参数的一个自定义方法
// 拼接请求
public String returnGetUrl(String url, Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
sb.append(url);
// 不同的后台 append后面的拼接不同
sb.append("&jsonstring=");
// sb.append(StringTools.correctEncode(returnGetPara(map)));
sb.append(returnGetPara(map));
return sb.toString();
}
BaseApplication.getRequestQueuemanager().add(mRequest);这句话大家应该能看明白吧 我当时说过 RequestQueue是在Application进行初始化。mRequest.setTag(tag);这句话就是设置Tag 好了 这就是一个请求。 responseInterface.successResponse(t, tag);这句话是我自定义一个接口 暴漏出请求到的数据(我们在外面Activity中只需要实现这个ResponseInterface 接口 注册一下就可以接收到我们返回的数据了)
// 请求接口
public interface ResponseInterface {
// 请求成功以后的回调
public <T> void successResponse(T parsedGSON, int tag);
// 请求失败的回调
public void errorResonse(String retmeg, int tag);
}
这时候你可能看的有点晕 这都哪跟哪啊 别急 我待会把我后台处理的三个类给大家贴出来 待会肯定明白
现在我们整个的自定义Request就讲完了 现在我把我做项目写的三个类给大家贴出来供大家参考 大家根据自己的需要去修改
package com.firstmortgage.net;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.util.Log;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyLog;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
/*
* 自定义Request 请求服务器 (Volley框架)T的类型是bean 这个地方解析数据的时候使用Gson,注意返回的Json字段名字一定要和Bean的字段对应起来
*/
public class GsonRequest<T> extends Request<T> {
/** Charset for request. */
private static final String PROTOCOL_CHARSET = "utf-8";
/** Content type for request. */
private static final String PROTOCOL_CONTENT_TYPE = String.format(
"application/json; charset=%s", PROTOCOL_CHARSET);
/* 解析方式 */
private Gson mGson;
// 上下文
private Context context;
// 监听器
private Listener<T> mListener;
// 泛型类(解析的Bean类型)
private Class<T> mClass;
// 上传的参数
private String mRequestBody;
/**
* params(参数)
*/
private Map<String, String> params = new HashMap<String, String>();
/**
* headers(头)
*/
private Map<String, String> headers = new HashMap<String, String>();
/**
* timeOut(设置超时时间 )
*/
private int timeOut = 35000;
/**
* 初始化的类型(mRequestBody是转换成JsonString的字符串)
*/
public GsonRequest(int method, String url, String mRequestBody,
Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mRequestBody = mRequestBody;
this.mListener = listener;
}
/**
* 初始化的类型
*/
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
}
/**
* 初始化的类型带Param
*/
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener,
Map<String, String> params) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
this.params = params;
}
// 设置超时
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(timeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
@Override
public String getBodyContentType() {
// TODO Auto-generated method stub
return PROTOCOL_CONTENT_TYPE;
}
// 添加header
private void setHeaders(String key, String value) {
headers.put(key, value);
}
// 设置超时时间
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
@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
public Map<String, String> getHeaders() throws AuthFailureError {
// TODO Auto-generated method stub
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
@Override
protected void deliverResponse(T t) {
mListener.onResponse(t);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
// 得到服务器返回的数据
String strObject = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
// 转化为泛型的对象
T parsedGSON = mGson.fromJson(strObject, mClass);
return Response.success(parsedGSON,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
Log.e("error", e.getMessage().toString());
return Response.error(new ParseError(e));
}
}
}
package com.firstmortgage.net;
import java.net.URLEncoder;
import java.util.Map;
import android.content.Context;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.Volley;
import com.firstmortgage.BaseApplication;
import com.firstmortgage.common.Constants;
import com.google.gson.Gson;
import com.squareup.okhttp.OkHttpClient;
//Request管类
public class RequestManager {
// 自定义接口
private ResponseInterface responseInterface;
// Gson解析
private Gson gson;
private OkHttpClient okHttpClient;
// 构造函数
private RequestManager(Context context) {
gson = new Gson();
okHttpClient = new OkHttpClient();
}
/**
* @param requestType
* 请求方式(GET or POST)
* @param url
* 请求的URL
* @param tag
* TAG
* @param map
* 传值
* @param cls
* 对象
* @param <T>
* 映射的类
*/
// 请求服务器
public <T> void requestGet(int requestType, String urlStr, final int tag,
Map<String, Object> map, Class<T> cls) {
GsonRequest<T> mRequest = new GsonRequest<T>(requestType, returnGetUrl(
urlStr, map), cls, new Listener<T>() {
@Override
public void onResponse(T t) {
responseInterface.successResponse(t, tag);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
responseInterface.errorResonse(arg0.getMessage(), tag);
}
});
mRequest.setTag(tag);
BaseApplication.getRequestQueuemanager().add(mRequest);
}
// 拼接请求(.net做后台 不同的后台 不同的拼接请求)
public String returnGetUrl(String url, Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
sb.append(url);
// 不同的后台 append后面的拼接不同
sb.append("&jsonstring=");
// sb.append(StringTools.correctEncode(returnGetPara(map)));
sb.append(returnGetPara(map));
return sb.toString();
}
// 拼接请求参数
public String returnGetPara(Map<String, Object> params) {
String utfStr = "";
try {
utfStr = URLEncoder.encode(gson.toJson(params), Constants.CodeType);
} catch (Exception e) {
utfStr = "";
}
return utfStr;
}
public static RequestQueue newRequestQueue(Context context) {
RequestQueue requestQueue;
HurlStack stack = new OkHttpStack();
requestQueue = Volley.newRequestQueue(context);
requestQueue.start();
return requestQueue;
}
// 注册
public void setResponseListener(ResponseInterface mResponseInterface) {
this.responseInterface = mResponseInterface;
}
// 请求接口
public interface ResponseInterface {
// 请求成功以后的回调
public <T> void successResponse(T parsedGSON, int tag);
// 请求失败的回调
public void errorResonse(String retmeg, int tag);
}
}
package com.firstmortgage;
import java.io.File;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import com.firstmortgage.net.OkHttpStack;
import com.firstmortgage.net.RequestManager;
import com.firstmortgage.util.ScreenManager;
import com.loopj.android.http.AsyncHttpClient;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.utils.StorageUtils;
import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
//程序入口
public class BaseApplication extends Application {
/**
* 单例
*/
private static BaseApplication mBaseApplication;
private Context context;
/**
* 管理所有的activity
*/
public ScreenManager mScreenManager = null;
/**
* 全局定义的RequestQueue(Volley使用)
*/
private static RequestQueue mRequestQueue;
// Vollery 管理器 单例
public static RequestQueue getRequestQueuemanager() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mBaseApplication);
}
return mRequestQueue;
}
// 单例的BaseApplication
public static BaseApplication getInstance() {
if (mBaseApplication == null) {
mBaseApplication = new BaseApplication();
}
return mBaseApplication;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mBaseApplication = this;
context = this;
}
}
我们在Activity使用的时候只需要让Activity implements ResponseInterface 然后会回调接口里面的两个成功跟失败的方法 还有重要的是 一定要注册一下mRequestManager = new RequestManager(); mRequestManager.setResponseListener(this);写在onCreat里面就可以了 (这里的注册只是针对我写这个 我为了方便将数据暴漏出来了 记住只是针对我写的这个我需要注册 大家根据自己的需要去写)
总结;
到这里我们这个完整的自定义Request就写完了
1.自定义GsonRequest继承Request实现里面的方法 parseNetworkResponse deliverResponse和构造函数我们必须要实现的 其他的根据自己的需要去实现
2.建议编程习惯好的人 去写一个RequestManager 专门管理咱们这个自定义的Request 然后定义一个接口把咱们请求的数据暴漏出去
好了 !!!明天咱们具体来看一下 Volley的整个框架 看一下内部是具体怎么实现的