按照惯例,github项目地址:https://github.com/xiaosixiong/RxJavaKj
写在前面
1. 首先来看看我们的项目结构:
- beans 不解释
- netapi 存放网络请求相关的apiService及服务器域名等
- netsubscribe 各个业务模块的网络请求订阅者
- netutils 封装了retrofit、数据请求结构、返回监听等,可以打成依赖库直接使用
- ui 各种activity fragment等
- 其他adapter、utils、views等
2. 封装后的调用如下
HomeSubscribe business = new HomeSubscribe();
business.getComment(this, new ResponseListener>() {
@Override
public void onNetFault(String errorMsg, int errorCode) {
}
@Override
public void onDataFault(String errorMsg, int errorCode) {
}
@Override
public void onDataSuccess(List data, String msg) {
}
});
是不是很简单?在activity中new 一个业务观察者HomeSubscribe,调用getComment方法,根据接口返回结果做不同的处理。系不系hin开心?
好了,退后,我要开始装B了!
1、引入依赖
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//下面两个是RxJava 和 RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
compile 'io.reactivex.rxjava2:rxjava:2.1.9'
//retrofit2 相关
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'//okhttplog
// view绑定
compile 'com.jakewharton:butterknife:8.4.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}
2、retrofit的封装
public class RetrofitManager {
private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
private static final int DEFAULT_READ_TIME_OUT = 10;
private Retrofit mRetrofit;
private RetrofitManager() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
} else {
interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
}
builder.addInterceptor(interceptor);
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BaseUrlConfig.BASE_URL_COMMENT)
.build();
}
private static class SingletonHolder {
private static final RetrofitManager INSTANCE = new RetrofitManager();
}
/**
* 获取retrofit实例
*
* @return
*/
public static RetrofitManager getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 获取对应的Serviceapi
*
* @param service Service 的 class
* @param
* @return
*/
public T create(Class service) {
return mRetrofit.create(service);
}
}
我们封装一个RetrofitManager类来构建单例的Retrofit,在这里你可以根据需求添加自己的网络配置,我们添加okhttp3自带的log拦截器,方便调试。
api = RetrofitManager.getInstance().create(HomeApiService.class);
通过调用泛型方法create,我们可以得到预先定义好的各模块的网络请求api,当然,如果有的项目不止有一个baseUrl,我们还可以封装一个RetrofitMultiBaseUrlManager类,代替RetrofitManager获取网络请求api,比如HomeSubscribe:
api2 = RetrofitMultiBaseUrlManager.getApiImp(BaseUrlConfig.BASE_URL_API, HomeApiService.class);
public interface HomeApiService {
/**
* 获取评论列表
* @param params
* @return
*/
@FormUrlEncoded
@POST("comment/get_new_comment")
Observable>> initComments(@FieldMap Map params);
/**
* 获取资讯
* @return
*/
@FormUrlEncoded
@POST("article/get_all_article")
Observable> initZixuns(@FieldMap Map params);
}
其中BaseResponse是我们定义的通用数据返回结构(这个根据自己项目需求修改)。
3、通用网络返回数据结构的封装
小编项目中的网络数据返回结构如下:status状态码、泛型数据data、服务端提示信息message、及错误码errorCode
public class BaseResponse {
private int status;
public T data;
int errorCode;
String message;
boolean isSuccess(){
return status == 1;
}
}
我们将期望得到的data和服务端返回的message进行封装,方便后续接口返回(其实是tm后加的,你装啥呀装,啊哈哈哈)
public class DataAndMessage {
private String msg;
private T data;
public DataAndMessage(String msg, T data) {
this.msg = msg;
this.data = data;
}
public String getMsg() {
return msg;
}
public T getData() {
return data;
}
}
4、网络返回监听接口封装
通常网络返回的数据分三种情况
- 1网络请求成功,获得期望数据data
- 2网络请求成功,未获取期望数据(比如用户没登录请求个人信息等)
- 3网络请求失败(断网或服务器挂掉等原因)
我们定义一个接口,ResponseListener来处理上述不同的情况,这个接口的调用及使用场景,我们在稍后解析
public interface ResponseListener {
// 网络错误,返回错误信息及错误码
void onNetFault(String errorMsg, int errorCode);
// 未请求到期望数据,返回服务端消息及错误码
void onDataFault(String errorMsg, int errorCode);
// 请求到期望数据,返回泛型数据及服务端消息
void onDataSuccess(T data, String msg);
}
- 注:根据项目需求可以统一处理网络错误
public abstract class DataResponseListener implements ResponseListener {
@Override
public void onNetFault(String errorMsg, int errorCode) {
//Todo 根据errorCode,统一处理网络问题导致的请求错误
}
}
- 注:可以统一处理数据错误,如统一处理需要用户登录跳转等
public abstract class DataSuccessResponseListener extends DataResponseListener {
@Override
public void onDataFault(String errorMsg, int errorCode) {
//Todo 统一处理数据错误码等
}
}
5、观察者与被观察者的封装
- 被观察者的封装
我们先来看被观察者
public class BaseObserver implements Observer> {
private ResponseListener listener;
/**
* @param listener回调监听
*/
public BaseObserver(ResponseListener listener) {
this.listener = listener;
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(DataAndMessage t) {
listener.onDataSuccess(t.getData(), t.getMsg());
}
/**
* 对错误进行统一处理
* 隐藏ProgressDialog
*/
@Override
public void onError(Throwable e) {
if (e instanceof DataFaultException) {
DataFaultException fault = (DataFaultException) e;
listener.onDataFault(fault.getMessage(), fault.getErrorCode());
return;
}
try {
if (e instanceof SocketTimeoutException) {//请求超时
listener.onNetFault("请求超时", 8);
} else if (e instanceof ConnectException) {//网络连接超时
listener.onNetFault("网络连接超时", 1);
} else if (e instanceof SSLHandshakeException) {//安全证书异常
listener.onNetFault("安全证书异常", 2);
} else if (e instanceof HttpException) {//请求的地址不存在
int code = ((HttpException) e).code();
if (code == 504) {
listener.onNetFault("网络异常,请检查您的网络状态", 3);
} else if (code == 404) {
listener.onNetFault("请求的地址不存在", 4);
} else {
listener.onNetFault("请求失败", 5);
}
} else if (e instanceof UnknownHostException) {
listener.onNetFault("域名解析失败", 6);
} else {
listener.onNetFault("error:" + e.getMessage(), 7);
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
我们定义一个继承Observer的类BaseObserver,处理各个订阅返回的结果,其实就是将不同的结果分发给我们前面定义的接口ResponseListener,我们这里继承的是一个DataAndMessage作为泛型的Observer,这个在前面提到过,为的是返回我们关心的泛型data和message提示,其它的返回我们均以error处理(这个在后面讲到)。这里我们定义一个数据错误异常DataFaultException,区分error类型,分发给ResponseListener的onDataFault还是onNetFault,这个数据异常类也很简单,只携带一个errorCode,一个message提示,没必要讲。
public class DataFaultException extends Exception {
private int errorCode;
public DataFaultException(int errorCode, String message) {
super(message);
this.errorCode=errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
- 观察者的封装
小编建议我们按照业务模块建立多个业务观察者,方便查找,将共同的代码部分提出来,建立一个BaseSubscribe,各个业务观察者继承这个BaseSubscribe。
比如前面我们开篇提到的主页模块的观察者HomeSubscribe,继承自BaseSubscribe,
public class HomeSubscribe extends BaseSubscribe {
private HomeApiService api;
private HomeApiService api2;
public HomeSubscribe() {
api = RetrofitManager.getInstance().create(HomeApiService.class);
api2 = RetrofitMultiBaseUrlManager.getApiImp(BaseUrlConfig.BASE_URL_API, HomeApiService.class);
}
public void getComment(Context context, final ResponseListener> listener) {
Map source = new HashMap<>();
toDetachAndSubscribe(api.initComments(source), listener);
}
public void getZixun(Context context, final ResponseListener listener) {
Map source = new HashMap<>();
source.put("device_type", "1");
toDetachAndSubscribe(api2.initZixuns(source), listener);
}
}
我们在HomeSubscribe中获取apiService返回的被观查者对象,交给父类统一处理数据拆分及统一订阅
public class BaseSubscribe {
protected void toDetachAndSubscribe(Observable extends BaseResponse> observable, ResponseListener listener) {
Observable> detachedObservable = detachDataAndMessageFrom(observable);
detachedObservable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<>(listener));
}
private Observable> detachDataAndMessageFrom(Observable extends BaseResponse> observable) {
return observable.map(new Function, DataAndMessage>() {
@Override
public DataAndMessage apply(BaseResponse tBaseResponse) throws Exception {
if (!tBaseResponse.isSuccess()) {
throw new DataFaultException(tBaseResponse.errorCode, tBaseResponse.message);
}
return new DataAndMessage<>(tBaseResponse.message, tBaseResponse.data);
}
});
}
}
看着这一推泛型参数,懵逼不?没办法,java中的泛型啊!。。。真香!
数据拆分:
private Observable> detachDataAndMessageFrom(Observable extends BaseResponse> observable) {
return observable.map(new Function, DataAndMessage>() {
@Override
public DataAndMessage apply(BaseResponse tBaseResponse) throws Exception {
if (!tBaseResponse.isSuccess()) {
throw new DataFaultException(tBaseResponse.errorCode, tBaseResponse.message);
}
return new DataAndMessage<>(tBaseResponse.message, tBaseResponse.data);
}
});
}
其实挺简单的,就是将我们网络请求返回的被观察对象做了个map处理,从BaseResponse
统一订阅:
detachedObservable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<>(listener));
这个就没什么好说的了,将数据拆分后的被观察者订阅给前面我们定义的观察者BaseObserver,同时传入回调地址,分发处理回调。