我们在做项目中,经常会用Retrofit网络请求框架。在最近的项目中我也在使用。由于一些接口数据的原因,所以自己做了一些封装避免了一些麻烦代码,然后在这里总结一下,这次的封装主要在于对于返回数据的状态码提取在成功前进行状态处理,只有请求成功才可以到业务层
了解更多请查看码云:链接
无敌分割线
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一、首先奉上RetrofitServiceManager的代码
此处为导入的依赖
api 'com.squareup.okhttp3:logging-interceptor:3.5.0'
api 'com.squareup.retrofit2:retrofit:2.3.0'
api 'com.squareup.retrofit2:converter-gson:2.3.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
api 'io.reactivex.rxjava2:rxjava:2.2.8'
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
这页代码,使用的单例,okhttp拦截器(经过封装的),同样也使用了泛型来处理了Retrofit的create方法
package com.song.retrofitrxjava.net;
import com.song.retrofitrxjava.net.converter.CustomGsonConverterFactory;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
public class RetrofitServiceManager {
private static final int DEFAULT_TIME_OUT = 5;
private static final int DEFAULT_READ_TIME_OUT = 10;
private Retrofit mRetrofit;
private RetrofitServiceManager() {
//创建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读取操作 超时时间
//添加公共参数拦截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("paltfrom", "android")
.addHeaderParams("userToken", "1234343434dfdfd3434") // TODO: 2019/4/16 添加认证信息
.builder();
builder.addInterceptor(commonInterceptor);
//打出日志的模式,Level.BODY 这里有很多样式的日志模式,个人觉的这里使用body更为方便
HttpLoggingInterceptor logging = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logging);
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(CustomGsonConverterFactory.create())//重新封装了Gson解析
.baseUrl(ApiConfig.BASE_URL)
.build();
}
private static class SingletonHolder {
private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager();
}
public static RetrofitServiceManager getInstance() {
return SingletonHolder.INSTANCE;
}
public <T> T create(Class<T> service) {
return mRetrofit.create(service);
}
}
OkHttp拦截器的类
package com.song.retrofitrxjava.net;
import android.util.Log;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class HttpCommonInterceptor implements Interceptor {
//利用集合Map来装我们Header
private Map<String, String> mHeaderParamsMap = new HashMap<>();
public HttpCommonInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Log.d("httpCommonInterceptor", "add common params");
Request oldRequest = chain.request();
//添加新参数,添加到url中
Request.Builder requestBuilder = oldRequest.newBuilder();
requestBuilder.method(oldRequest.method(), oldRequest.body());
if (mHeaderParamsMap.size() > 0) {
for (Map.Entry<String, String> params : mHeaderParamsMap.entrySet()) {
requestBuilder.header(params.getKey(), params.getValue());
}
}
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
public static class Builder {
HttpCommonInterceptor mHttpCommonInterceptor;
public Builder() {
mHttpCommonInterceptor = new HttpCommonInterceptor();
}
public Builder addHeaderParams(String key, String value) {
mHttpCommonInterceptor.mHeaderParamsMap.put(key, value);
return this;
}
public HttpCommonInterceptor builder() {
return mHttpCommonInterceptor;
}
}
}
二、对于Gson的封装修改
package com.song.retrofitrxjava.net.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public class CustomGsonConverterFactory extends Converter.Factory {
private final Gson gson;
private CustomGsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
//此处使用create模式 所以写出create()和create(Gson gson) 方法
public static CustomGsonConverterFactory create() {
return create(new Gson());
}
public static CustomGsonConverterFactory create(Gson gson) {
return new CustomGsonConverterFactory(gson);
}
//对返回数据的gson过滤封装
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
//这里通过数据的Type类型来选取adapter,这里看不懂的可以点击进去查看Gson的源码
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonResponseBodyConverter<>(gson, adapter);
}
//对请求数据的gson封装
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CustomGsonRequestBodyConverter<>(gson, adapter);
}
}
附加Gson返回数据过滤封装类和Gson请求数据过滤封装类
package com.song.retrofitrxjava.net.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.song.retrofitrxjava.exception.ApiException;
import com.song.retrofitrxjava.net.entity.HttpStatus;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import retrofit2.Converter;
final public class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
//返回数据状态码的提取
HttpStatus httpStatus = gson.fromJson(response, HttpStatus.class);
if (!httpStatus.isStatusNormal()) { // 状态码异常
value.close();
// if (httpStatus.isTokenInvalid()) { // token失效
// RxBus.getInstance().post(new BadTokenEvent());
// }
throw new ApiException(httpStatus.getCode(), httpStatus.getMsg());
}
MediaType contentType = value.contentType();
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
InputStream inputStream = new ByteArrayInputStream(response.getBytes());
Reader reader = new InputStreamReader(inputStream, charset);
JsonReader jsonReader = gson.newJsonReader(reader);
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
package com.song.retrofitrxjava.net.converter;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import retrofit2.Converter;
final public class CustomGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
CustomGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
三、封装之后的使用
//注意一点:这里Map<String,Map<String,String>>是我返回数据中data字段的数据
由于我这里的返回数据是map,所以这里不可以用类去接收,所以使用了map,在我们做项目的时候会遇到,很多奇葩的返回数据,而这里返回的map数据就是一种,应为数据是以汉字作为字段的数据。在后面的博客中我会单独的说明
//注意一点:这里Map<String,Map<String,String>>是我返回数据中data字段的数据
RetrofitServiceManager.getInstance().create(TestService.class).getResourceClassificationStatistic()
.map(new ResultFilter<Map<String, Map<String, String>>>())
.compose(RxScheduler.<Map<String, Map<String, String>>>ioMain())
.subscribe(new RequestCallBack<Map<String, Map<String, String>>>(this) {
@Override
public void onBefore(Disposable d) {
}
@Override
public void onSuccess(Map<String, Map<String, String>> data) {
Set<Map.Entry<String, Map<String, String>>> entries = data.entrySet();
Iterator<Map.Entry<String, Map<String, String>>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Map<String, String>> next = iterator.next();
String key = next.getKey();
Toast.makeText(MainActivity.this, key, Toast.LENGTH_SHORT).show();
}
}
});
我这里的service是这样写的
public interface TestService {
/**
*
*/
@POST("")
Observable<BaseEntity<Map<String, Map<String, String>>>> getResourceClassificationStatistic();
}
BaseEntity对相同的返回的状态的数据进行了统一处理
在这里我们的BaseEntity继承了之前说过的HttpStatus对于请求状态的统一处理类
package com.song.retrofitrxjava.net.entity;
import com.google.gson.annotations.SerializedName;
public class BaseEntity<T> extends HttpStatus {
@SerializedName("data")
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
ResultFilter是Function的封装,这里处理的是data,将状态数据过滤,只要data
package com.song.retrofitrxjava.rx;
import com.song.retrofitrxjava.net.entity.BaseEntity;
import io.reactivex.functions.Function;
public class ResultFilter<T> implements Function<BaseEntity<T>, T> {
@Override
public T apply(BaseEntity<T> baseEntity) throws Exception {
return baseEntity.getData();
}
}
对线程的处理
package com.song.retrofitrxjava.rx;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class RxScheduler {
public static <T> ObservableTransformer<T, T> ioMain() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.unsubscribeOn(Schedulers.io())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
返回callback的处理
package com.song.retrofitrxjava.callback;
import android.content.Context;
import com.song.retrofitrxjava.util.NetUtils;
import com.song.retrofitrxjava.util.ToastUtils;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
public abstract class RequestCallBack<T> implements Observer<T> {
private final Context context;
private Disposable disposable;
public RequestCallBack(Context ctx) {
this.context = ctx;
}
/**
* 订阅时回调
* @param d 用来终止订阅关系,由调用者处理,暴露出来防止内存泄露.
*/
public abstract void onBefore(Disposable d);
public abstract void onSuccess(T data);
public void onError(String errorMsg) {
ToastUtils.showShortToast(context, errorMsg);
}
public void onAfter() {}
protected Disposable getDisposable() {
return disposable;
}
@Override
final public void onSubscribe(Disposable d) {
this.disposable = d;
this.onBefore(d);
}
@Override
final public void onComplete() {
this.onAfter();
}
@Override
final public void onError(Throwable e) {
e.printStackTrace();
this.onError(NetUtils.analyzeNetworkError(context, e));
this.onAfter();
}
@Override
final public void onNext(T data) {
this.onSuccess(data);
}
}