本来在项目中是使用了Volley 然后封装 封装了一个HttpUtils,
但是由于项目中要引入RxJava,所以就顺便替换一下Volley,使用Retrofit+RxJava。
Volley框架,我这里就 不过多介绍了,大家如果想学习的会可以自己去了解下。
http://blog.csdn.net/ysh06201418/article/details/46443235
首先大家可以参考下其他的Retrofit+RxJava的使用方法。
http://blog.csdn.net/byxyrq/article/details/52672202
如果大家对RxJava还不大了解的话,大家可以看下这篇文章。
http://gank.io/post/560e15be2dca930e00da1083
下面我介绍下我是如何封装Retrofit+RxJava的。
这是我公司的后台返回的json数据格式:
{
data:返回的数据,
errorCode:200,
moreInfo:"错误详情"
}
其中'data'中返回的才是我们真正需要的内容,而‘errorCode’不为200,则是后台出错,具体错误信息放在‘moreInfo’中。 而如果直接使用Retrofit+RxJava。如下:
/**
* 登录
*/
@POST
@FormUrlEncoded
Observable login(@Url String url , @FieldMap Mapparam);
如果直接使用该接口,那么需要后台直接返回‘UserVO’的json数据。 但是依照前面所说,后台所有的返回数据都是依照
{
data:返回的数据,
errorCode:200,
moreInfo:"错误详情"
}
这种格式的数据返回。所以请求这个接口后,其实真正返回的数据应该是如下这样:
{
data:{UserVO对象},
errorCode:200,
moreInfo:"错误详情"
}
如上只是一个例子而已,其实所有接口,都是依照这种格式回传,所以在Retrofit+RxJava框架对返回的数据
进行处理之前,需要自己提前处理一下,先判断'errorCode'是否为200,如果为200就是正常请求数据返回,然后
获取到data的数据返回给Retrofit+RxJava框架进行处理。如果不为200,则为错误,根据错误的类型进行相应的处理。
如下:
/**
* 统一处理原始数据
*
* @param originalResponse
*/
private static Response dealResponseData(Response originalResponse) {
String jsonString = null;
try {
BufferedSource bufferedSource = originalResponse.body().source();
jsonString = bufferedSource.readString(Charset.forName("utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
if (!jsonString.trim().startsWith("{") && !jsonString.trim().startsWith("[")) {
return onSuccess(originalResponse, jsonString);
}
ResponseMessageBean msgBean = ResponseMessageBean.analyseReponse(jsonString);
if (msgBean == null) return onSuccess(originalResponse, msgBean.data.toString());
if (msgBean != null && (msgBean.errorCode == 200)) {
showError = true;
if (msgBean.data != null) {
return onSuccess(originalResponse, msgBean.data.toString());
} else {
return originalResponse.newBuilder().body(null).build();
}
} else {
onFailed(msgBean);
throw new RuntimeException(msgBean.moreInfo.toString());
}
}
请求之后返回一个Response对象,预先处理完成之后返回另一新的Response对象,这样就可以实现刚才的目的了。 ResponseMessageBean其实就是最外面的对象。
onSuccess方法中,其实主要对处理后的数据重新组装成一个新的Response对象
private static Response onSuccess(Response originalResponse, String content) {
return originalResponse.newBuilder().
body(ResponseBody.create(null, content)).
build();
}
方法虽然简单,但是这里要注意一点,不能新建一个新的Response返回,因为你Response里面其实是有多数据的,你就使用原来的Response, 然后把body里面的内容替换下就好了。
其实这里还有一个onFailed方法,主要是后台请求报错了,没有返回200,就根据你自己后台定义的值来判断具体错误,然后具体处理,这里
我就不再具体描述了。
前面描述的是data返回值是一个对象,其实是一个数组也是一样的,只要你在泛型里面写的是List那么就会返回一个List对象,如下:
@POST
@FormUrlEncoded
Observable> userList(@Url String url , @FieldMap Mapparam);
这样处理的数据其实是这种格式的
{
data:[{},{}],
errorCode:200,
moreInfo:"错误详情"
}
对了,我这里一直没有讲为什么Retrofit+RxJava会对返回的对象进行自动转换,因为我前面已经放了几篇文章,希望大家能先阅读了
一些基础的知识后,再来看这篇文章的具体封装,可能对你的帮助会更大一点。
Retrofit在初始化:
Retrofit retrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASEURL).
addConverterFactory(GsonConverterFactory.create()).
addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
client(mOkHttpClient).
build();
addConverterFactory其实是为了对返回内容的提供一个转换器。
这里官方实现了很多种转换器,如下
Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml
一共有这么几种,大家可以根据自己的返回格式和喜好,选择对应的转换器,我这里选择了Gson转换器。 记得选择转换器,要引入对应的依赖,这里我就不再过多赘述了。
我这里为什么要讲这个转换器呢?因为在项目的的过程中,我发现了有这样的一个需求,就是返回值中的data不是对象,也不是数组,
如下:
{
data:"你好",
errorCode:200,
moreInfo:"错误详情"
}
或者是其他‘boolean’,‘int’等基础类型。就会出错。所以我这里重新对gson转换器做了封装,如下
public class TWGsonResponseBodyConverter implements Converter {private final Gson gson;
private final TypeAdapter adapter;
private final TypeToken> typeToken;
TWGsonResponseBodyConverter(Gson gson, TypeAdapter adapter, TypeToken> typeToken) {
this.gson = gson;
this.adapter = adapter;
this.typeToken = typeToken;
}@Override
public T convert(ResponseBody value) throws IOException {
Object obj = checkBasicType(value);
if (obj != null) return (T) obj;
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}/**
* 如果是基本类型就转化后,返回
*/
private Object checkBasicType(ResponseBody value) throws IOException {
String typeName = typeToken.getRawType().getSimpleName();
if ("String".equals(typeName)) {
return value.string();
} else if ("Boolean".equals(typeName)) {
return Boolean.parseBoolean(value.string());
} else if ("Integer".equals(typeName)) {
return Integer.parseInt(value.string());
}
return null;
}
}
在方法中判断是否为基础类型,如果为基础类型,或者String 就通过处理后,直接返回,如果不是,则还是通过原来的转换器转换。 这样子就可以适用所有情况了。
在我的项目中,有一个场景,就是需要在请求时,自定义请求头,虽然Retrofit有@Head,但是由于每次请求都需要设置,还是直接封装
在里面比较好,代码如下:
private static Request.Builder createRequestHeader(Request.Builder builder) {
builder.header("Content-Type",
"application/x-www-form-urlencoded");
builder.header("User-Agent", getUserAgent());
return builder;
}
其实就是创建一个新的Request返回而已。 然后项目中又说要使用https来访问,所以我又加了下面的代码来支持:
if (mOkHttpClient == null) {
try {
X509TrustManager xtm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] x509Certificates = new X509Certificate[0];
return x509Certificates;
}
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// 指定缓存路径,缓存大小100Mb
Cache cache = new Cache(new File(mContext.getCacheDir(), "HttpCache"), 1024 * 1024 * 100);
mOkHttpClient = new OkHttpClient.Builder().
addInterceptor(mRewriteCacheControlInterceptor).
retryOnConnectionFailure(false).
connectTimeout(30, TimeUnit.SECONDS).
sslSocketFactory(sslContext.getSocketFactory()).
hostnameVerifier(DO_NOT_VERIFY).
cache(cache).
build();
} catch (Exception e) {
e.printStackTrace();
}
}
}
并且还指定了缓存还有超时时间,重试次数,等等。
以上情况其实已经适用我当前项目的所以场景了。
下面是附上所有代码:
public class RetrofitHelper {
private static ServerApi api;
private static OkHttpClient mOkHttpClient;
private static Context mContext;
private static boolean showError = true;
/**
* 启动后初始化
*/
public static void init(Context context) {
mContext = context;
initOkHttpClient();
Retrofit retrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASEURL).
addConverterFactory(GsonConverterFactory.create()).
addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
client(mOkHttpClient).
build();
api = retrofit.create(ServerApi.class);
}/**
* 重置baseUrl
*/
public static void resetBaseUrl() {
Retrofit retrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASEURL).
addConverterFactory(TWGsonConverterFactory.create()).
addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
client(mOkHttpClient).
build();
api = retrofit.create(ServerApi.class);
}public static ServerApi getApi() {
return api;
}/**
* 统一处理原始数据
*
* @param originalResponse
*/
private static Response dealResponseData(Response originalResponse) {
String jsonString = null;
try {
BufferedSource bufferedSource = originalResponse.body().source();
jsonString = bufferedSource.readString(Charset.forName("utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
if (!jsonString.trim().startsWith("{") && !jsonString.trim().startsWith("[")) {
return onSuccess(originalResponse, jsonString);
}
ResponseMessageBean msgBean = ResponseMessageBean.analyseReponse(jsonString);
if (msgBean == null) return onSuccess(originalResponse, msgBean.data.toString());
if (msgBean != null && (msgBean.errorCode == 200)) {
showError = true;
if (msgBean.data != null) {
return onSuccess(originalResponse, msgBean.data.toString());
} else {
return originalResponse.newBuilder().body(null).build();
}
} else {
onFailed(msgBean);
throw new RuntimeException(msgBean.moreInfo.toString());
}
}/**
* 初始化okHttp
*/
private static void initOkHttpClient() {
if (mOkHttpClient == null) {
synchronized (RetrofitHelper.class) {
Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetworkUtils.isNetworkConnected(mContext)) {
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
/**
* 统一设置请求头
*/
Request newRequest = createRequestHeader(request.newBuilder()).build();
Response originalResponse = chain.proceed(newRequest);
//如果是重定向,那么就执行重定向后返回数据。
if (originalResponse.isRedirect()) {
Request redirectRequest = request.newBuilder().url(originalResponse.header("location")).build();
originalResponse = chain.proceed(redirectRequest);
}
originalResponse = dealResponseData(originalResponse);
return originalResponse;
}
};
if (mOkHttpClient == null) {
try {
X509TrustManager xtm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] x509Certificates = new X509Certificate[0];
return x509Certificates;
}
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// 指定缓存路径,缓存大小100Mb
Cache cache = new Cache(new File(mContext.getCacheDir(), "HttpCache"), 1024 * 1024 * 100);
mOkHttpClient = new OkHttpClient.Builder().
addInterceptor(mRewriteCacheControlInterceptor).
retryOnConnectionFailure(false).
connectTimeout(30, TimeUnit.SECONDS).
sslSocketFactory(sslContext.getSocketFactory()).
hostnameVerifier(DO_NOT_VERIFY).
cache(cache).
build();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}private static Response onSuccess(Response originalResponse, String content) {
return originalResponse.newBuilder().
body(ResponseBody.create(null, content)).
build();
}/**
* errorCode 不为200
*
* @param msgBean
*/
private static void onFailed(ResponseMessageBean msgBean) {
String alert = "";
if (msgBean == null) {
return;
}
if (msgBean.errorCode != 200) {
if (msgBean.errorCode == 401) {
Observable.create(new Observable.OnSubscribe
【Retrofit+RxJava 完美封装】