rxjava2+ retrofit2的封装及使用

按照惯例,github项目地址:https://github.com/xiaosixiong/RxJavaKj

写在前面

1. 首先来看看我们的项目结构:
rxjava2+ retrofit2的封装及使用_第1张图片
image.png
  • 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> 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> 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> 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转换为我们关心的DataAndMessage。如果数据错误(status!=1)我们就抛数据错误异常,否则返回DataAndMessage,携带data及message。

统一订阅:

detachedObservable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseObserver<>(listener));

这个就没什么好说的了,将数据拆分后的被观察者订阅给前面我们定义的观察者BaseObserver,同时传入回调地址,分发处理回调。

好了,至此rxjava2+ retrofit2的封装及使用到此讲完了,有需要改进的地方,还请各位斧正!

你可能感兴趣的:(rxjava2+ retrofit2的封装及使用)