RxJava2+Retrofit2实现网络请求封装

网络请求一般会封装在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) {

                    }
                })
        );

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容