RxJava2+Retrofit2实现网络请求封装

作者: Android_惜年 | 来源:发表于2017-04-05 16:41 被阅读5808次

    网络请求一般会封装在Library的Module中,为了尽量简化网络请求的代码,使用Retrofit2结合RxJava2做了封装。

    引入依赖

    compile 'com.squareup.retrofit2:retrofit:2.2.0'
    compile 'com.squareup.retrofit2:converter-gson:2.2.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
    compile 'io.reactivex.rxjava2:rxjava:2.0.8'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.google.code.gson:gson:2.8.0'
    compile 'org.greenrobot:eventbus:3.0.0'
    

    在自定义的Application中定义BaseUrl、公共请求头、公共请求参数的抽象方法

    /**
     * 配置网络请求根路径
     */
    public abstract String getBaseUrl();
    
    /**
     * 配置网络请求头
     */
    public abstract ArrayMap<String, String> getRequestHeader();
    
    /**
     * 配置公共请求参数
     */
    public abstract ArrayMap<String, String> getRequestParams();
    

    定义静态属性

    public class Constants {
        public static final int NET_CODE_SUCCESS = 0;
        public static final int NET_CODE_ERROR = 1;
    
        public static final int NET_CODE_CONNECT = 400;
        public static final int NET_CODE_UNKNOWN_HOST = 401;
        public static final int NET_CODE_SOCKET_TIMEOUT = 402;
    
        public static final String CONNECT_EXCEPTION = "网络连接异常,请检查您的网络状态";
        public static final String SOCKET_TIMEOUT_EXCEPTION = "网络连接超时,请检查您的网络状态,稍后重试";
        public static final String UNKNOWN_HOST_EXCEPTION = "网络异常,请检查您的网络状态";
    }
    

    定义统一的请求结果解析

    public class Result<T> implements Serializable {
        private int code;
        private String msg;
        private T data;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    

    定义拦截器

    获取自定义Application中返回的公共请求头

    public class HeaderInterceptor implements Interceptor {
        @Override public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            ArrayMap<String, String> headers = BaseApp.getAppContext().getRequestHeader();
            //如果公共请求头不为空,则构建新的请求
            if (headers != null) {
                Request.Builder requestBuilder = originalRequest.newBuilder();
    
                for (String key : headers.keySet()) {
                    requestBuilder.addHeader(key, headers.get(key));
                }
                requestBuilder.method(originalRequest.method(), originalRequest.body());
                return chain.proceed(requestBuilder.build());
            }
            return chain.proceed(originalRequest);
        }
    }
    

    获取自定义Application中返回的公共请求参数

    public class ParamsInterceptor implements Interceptor {
        @Override public Response intercept(Chain chain) throws IOException {
            Request oldRequest = chain.request();
            ArrayMap<String, String> params = BaseApp.getAppContext().getRequestParams();
            //如果公共请求参数不为空,则构建新的请求
            if (params != null) {
                Request.Builder newRequestBuilder = oldRequest.newBuilder();
                //GET请求则使用HttpUrl.Builder来构建
                if ("GET".equalsIgnoreCase(oldRequest.method())) {
                    HttpUrl.Builder httpUrlBuilder = oldRequest.url().newBuilder();
                    for (String key : params.keySet()) {
                        httpUrlBuilder.addQueryParameter(key, params.get(key));
                    }
                    newRequestBuilder.url(httpUrlBuilder.build());
                } else {
                    //如果原请求是表单请求
                    if (oldRequest.body() instanceof FormBody) {
                        FormBody.Builder formBodyBuilder = new FormBody.Builder();
                        for (String key : params.keySet()) {
                            formBodyBuilder.add(key, params.get(key));
                        }
                        FormBody oldFormBody = (FormBody) oldRequest.body();
                        int size = oldFormBody.size();
                        for (int i = 0; i < size; i++) {
                            formBodyBuilder.add(oldFormBody.name(i), oldFormBody.value(i));
                        }
                        newRequestBuilder.post(formBodyBuilder.build());
                    }
                    // TODO:  处理其它类型的request.body
                }
                return chain.proceed(newRequestBuilder.build());
            }
            return chain.proceed(oldRequest);
        }
    }
    

    定义Subscriber

    public abstract class BaseSubscriber<T> extends DisposableSubscriber<Result<T>> {
    
        @Override public void onNext(Result<T> result) {
            //业务代码为成功则将具体的数据返回,否则利用EventBus将错误发出去
            if (result.getCode() == Constants.NET_CODE_SUCCESS) {
                handlerSuccess(result.getData());
            } else {
                EventBus.getDefault().post(new MsgEvent(result.getCode(), result.getMsg()));
            }
        }
    
        @Override public void onError(Throwable t) {
            MsgEvent msgEvent;
            //处理常见的几种连接错误
            if (t instanceof SocketTimeoutException) {
                msgEvent = new MsgEvent(Constants.NET_CODE_SOCKET_TIMEOUT, Constants.SOCKET_TIMEOUT_EXCEPTION);
            } else if (t instanceof ConnectException) {
                msgEvent = new MsgEvent(Constants.NET_CODE_CONNECT, Constants.CONNECT_EXCEPTION);
            } else if (t instanceof UnknownHostException) {
                msgEvent = new MsgEvent(Constants.NET_CODE_UNKNOWN_HOST, Constants.UNKNOWN_HOST_EXCEPTION);
            } else {
                msgEvent = new MsgEvent(Constants.NET_CODE_ERROR, t.getMessage());
            }
            EventBus.getDefault().post(msgEvent);
        }
    
        @Override public void onComplete() {
    
        }
    
        //请求成功返回结果
        public abstract void handlerSuccess(T t);
    }
    

    带有进度条的Subscriber

    public abstract class ProgressSubscriber<T> extends BaseSubscriber<T> {
        private ProgressDialog dialog;
    
         protected ProgressSubscriber(ProgressDialog dialog) {
            this.dialog = dialog;
        }
    
        @Override public void onError(Throwable e) {
            super.onError(e);
            if (dialog != null) dialog.dismiss();
        }
    
        @Override public void onComplete() {
            super.onComplete();
            if (dialog != null) dialog.dismiss();
        }
    }
    

    为了对请求进行预处理和简化每次都要写的线程步骤,定义了如下的一个类

    public class RxSchedulers {
        /**
         * 基本请求
         */
        public static <T> FlowableTransformer<T, T> io_main(final Context context) {
            return new FlowableTransformer<T, T>() {
                @Override public Publisher<T> apply(@NonNull Flowable<T> upstream) {
                    return upstream
                            .subscribeOn(Schedulers.io())
                            .doOnSubscribe(new Consumer<Subscription>() {
                                @Override
                                public void accept(@NonNull Subscription subscription) throws Exception {
                                    //如果无网络连接,则直接取消了
                                    if (!NetUtil.isConnected(context)) {
                                        subscription.cancel();
                                        MsgEvent msgEvent = new MsgEvent(Constants.NET_CODE_CONNECT, Constants.CONNECT_EXCEPTION);
                                        EventBus.getDefault().post(msgEvent);
                                    }
                                }
                            })
                            .observeOn(AndroidSchedulers.mainThread());
                }
            };
        }
    
        /**
         * 带进度条的请求
         */
        public static <T> FlowableTransformer<T, T> io_main(final Context context, final ProgressDialog dialog) {
            return new FlowableTransformer<T, T>() {
                @Override public Publisher<T> apply(@NonNull Flowable<T> upstream) {
                    return upstream
                            //为了让进度条保持一会儿做了个延时
                            .delay(1, TimeUnit.SECONDS) 
                            .subscribeOn(Schedulers.io())
                            .doOnSubscribe(new Consumer<Subscription>() {
                                @Override
                                public void accept(@NonNull final Subscription subscription) throws Exception {
                                    if (!NetUtil.isConnected(context)) {
                                        subscription.cancel();
                                        MsgEvent msgEvent = new MsgEvent(Constants.NET_CODE_CONNECT, Constants.CONNECT_EXCEPTION);
                                        EventBus.getDefault().post(msgEvent);
                                    } else {
                                        //启动进度显示,取消进度时会取消请求
                                        if (dialog != null) {
                                            dialog.setCanceledOnTouchOutside(false);
                                            dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                                                @Override public void onCancel(DialogInterface dialog) {
                                                    subscription.cancel();
                                                }
                                            });
                                            dialog.show();
                                        }
                                    }
                                }
                            })
                            .observeOn(AndroidSchedulers.mainThread());
                }
            };
        }
    }
    
    

    定义retrofit的单例,结合Android的生命周期来管理订阅

    public class RetrofitManager {
        private static ArrayMap<String, CompositeDisposable> netManager = new ArrayMap<>();
    
        public static Retrofit getInstance() {
            return Instance.retrofit;
        }
    
        private static class Instance {
            private static String baseUrl = BaseApp.getAppContext().getBaseUrl();
            private static Retrofit retrofit = getRetrofit();
    
            private static Retrofit getRetrofit() {
                OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
                //debug模式添加log信息拦截
                if (BaseApp.getAppContext().isDebug()) {
                    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                    okHttpBuilder.addInterceptor(interceptor);
                }
                okHttpBuilder.addInterceptor(new HeaderInterceptor());
                okHttpBuilder.addInterceptor(new ParamsInterceptor());
                //设置网络连接失败时自动重试
                okHttpBuilder.retryOnConnectionFailure(true);
                //设置连接超时
                okHttpBuilder.connectTimeout(5, TimeUnit.SECONDS);
                //设置写超时
                okHttpBuilder.writeTimeout(10, TimeUnit.SECONDS);
                //设置读超时
                okHttpBuilder.readTimeout(10, TimeUnit.SECONDS);
    
    
                Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
                retrofitBuilder.baseUrl(baseUrl);
                retrofitBuilder.client(okHttpBuilder.build());
                retrofitBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
                retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
                return retrofitBuilder.build();
            }
        }
    
        //为了避免错误的取消了,key建议使用packagename + calssName
        public static void add(String key, Disposable disposable) {
            if (netManager.containsKey(key)) {
                netManager.get(key).add(disposable);
            } else {
                CompositeDisposable compositeDisposable = new CompositeDisposable();
                compositeDisposable.add(disposable);
                netManager.put(key, compositeDisposable);
            }
        }
    
        public static void remove(String key) {
            if (netManager.containsKey(key)) {
                CompositeDisposable compositeDisposable = netManager.get(key);
                compositeDisposable.clear();
            }
        }
    }
    

    BaseActivity中的配置

    
        @Override protected void onResume() {
            super.onResume();
            EventBus.getDefault().register(this);
        }
    
        @Override protected void onPause() {
            super.onPause();
            EventBus.getDefault().unregister(this);
        }
    
        @Override protected void onDestroy() {
            super.onDestroy();
            String key = mContext.getPackageName() + "." + mContext.getClass().getSimpleName();
            RetrofitManager.remove(key);
        }
    
        protected void addDisposable(Disposable disposable) {
            String key = mContext.getPackageName() + "." + mContext.getClass().getSimpleName();
            RetrofitManager.add(key, disposable);
        }
    

    简单使用

    1. 定义接口
     @GET("api/common/getQiNiuToken")
    Flowable<Result<String>> getQiNiuToken();
    
    1. 网络请求调起
    //不带进度的网络请求
    addDisposable(RetrofitManager.getInstance()
                    .create(ICommon.class)
                    .getQiNiuToken()
                    .compose(RxSchedulers.<Result<String>>io_main(mContext))
                    .subscribeWith(new BaseSubscriber<String>() {
                        @Override public void handlerSuccess(String s) {
    
                        }
                    })
            );
    //带进度的网络请求
    ProgressDialog dialog = new ProgressDialog(mContext, ProgressDialog.THEME_HOLO_DARK);
    dialog.setMessage("请稍后。。。");
    
    addDisposable(RetrofitManager.getInstance()
                    .create(ICommon.class)
                    .getQiNiuToken()
                    .compose(RxSchedulers.<Result<String>>io_main(mContext, dialog))
                    .subscribeWith(new ProgressSubscriber<String>(dialog) {
                        @Override public void handlerSuccess(String s) {
    
                        }
                    })
            );
    

    以上就是我的网络请求封装全部代码。

    相关文章

      网友评论

      • 風語_6300:把联网取数据的UI 放在自定义Subscriber里的封装思路很赞啊,解决了我困扰多日的问题
        Android_惜年:@風語_6300 谢谢夸赞:smile: https://github.com/timordu/Rely-kotlin 这个是kotlin版本的
      • 因帅被判刑:大佬有java版的demo么
        Android_惜年:@因帅被判刑 https://github.com/timordu/Rely 這個是之前從項目中抽取出來的,你可以參考下
        因帅被判刑:@Android_惜年 好吧 不能看到大佬的代码了 179098051@qq.com
        Android_惜年:@因帅被判刑 我没写demo哟,直接在项目中验证的
      • hirezy:不错,可以有完整的代码参考吗
        Android_惜年:@hirezy https://github.com/timordu/Rely-kotlin 这个kotlin版本的 代码基本上差不多,java版本的是在实际项目中比较乱,不太好抽取出来
      • Jpacino:能发我一份demo吗,jpacino@163.com,谢谢啦。
        Android_惜年:@Jpacino Java版的没有具体的demo,是从项目里面直接拷贝出来的代码
      • 焦27:我通过你的写法Result<T>,子类继承该类后,请求的回调 result.getData值是空的
        焦27:public class BaseEntity<T> {
        private int code;
        private String msg;

        private T result;
        }

        @get("api/v1/common/index")
        Flowable<BaseEntity<City>> region();

        BaseRetrofit
        .getInstance()
        .create(BaseRetrofitApi.class)
        .region()
        .compose(BaseRxSchedulers.<BaseEntity<City>>io_main(this))
        .subscribeWith(new BaseSubscriber<City>() {
        @Override
        public void onSuccess(City city) {
        LogUtils.e(city.getData().get(0).getBIANMA());
        }
        });

        @Override
        public void onNext(BaseEntity<T> baseEntity) {
        if (baseEntity.getCode() == Constants.NET_CODE_SUCCESS) {
        onSuccess(baseEntity.getResult());
        } else {
        ToastUtils.showToast(baseEntity.getMsg());
        }
        }
        Android_惜年:对应json 你可以看出 实体类应该是Result类中的一部分
        Android_惜年:这个不应该产生继承的哈, 接口类中 应该是 Observable<Result<User>> 这样声明, T是一个泛型,指的就是各种定义的实体类
      • _孑孓_:版本的问题 java.lang.NoSuchMethodError: No virtual method isSuccessful()Z in class Lretrofit2/Response; or its super classes (declaration of 'retrofit2.Response' appears in /data/app/com.moon.samples-2/base.apk)

        我的配置是这样的
        compile 'com.squareup.retrofit2:retrofit:2.2.0'
        compile 'com.squareup.retrofit2:converter-gson:2.2.0'
        compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
        compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
        compile 'io.reactivex.rxjava2:rxjava:2.0.8'
        compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
        Android_惜年:哈哈, 有时候就是会被IDE坑一把:smile:
        _孑孓_:@Android_惜年 好了, 之前编译的东西没有重新跑, 我把build里的class 删掉了 重新编译解决了,捣鼓了挺久
        Android_惜年: @SpritMoon 这个问题我没遇到过,我明天上班的时候看看代码
      • Minzou丶怪兽:感谢楼主分享,慢慢的习惯RxJava2了
      • 适当车:感谢分享
      • Android_惜年:我把我的library的代码和build.gradle代码提交到了github上,后期会给上完整的项目..https://github.com/timordu/Rely
      • o执笔写青春o:有demo吗,给个地址,谢谢
        Android_惜年:@o执笔写青春o 发你了哈
        o执笔写青春o:@Android_惜年 sinianyingzijoy@163.com谢谢:smile:
        Android_惜年:@o执笔写青春o 没有哦 ,我自己也还在项目中实验,如果需要 我可以单独给你发 留个邮箱吧
      • 曾经的你呀:不错,还是RxJava2 !
      • b09dbea7de6a:还不错
        b09dbea7de6a:@Android_惜年 加油
        Android_惜年:这两天还在折腾升级版的,弄好了继续分享

      本文标题:RxJava2+Retrofit2实现网络请求封装

      本文链接:https://www.haomeiwen.com/subject/mnhxattx.html