RxJava+Retrofit 史上最精简封装(RxHttpUtils 2.x)如何封装

我们都是知道Android开发必不可少的网络请求框架这几年经历了几次变更 android-async-http---->Volley、XUtils---->OkHttp---->Retrofit,这两年RxJava的流行让Retrofit着实火了一把,身为合格的Android开发人员要是对它不了解还真有点说不过去。

开篇

我是在去年的时候开始接触RxJava+Retrofit的,那时候还是RxJava1.x的版本,当时根据需求自己简单封装了一个网络库RxHttpUtils,因为只是针对公司项目的需求做的封装,所以有些局限性。可拓展性也不是很好(但是针对公司项目已经够用了),就这样那次封装之后就没怎么修改过相关代码了。
近期正好又开了新项目,网络请求这块后台有些变化,之前的网络框架不能满足了,加上RxJava2都已经出来了,所以就有了基于RxJava2重新封装的想法,这几天对RxHttpUtils1.x重构了一下,需要了解怎么使用的可以直接看RxHttpUtils 2.x里边有详细的使用说明,而且我也建议先看看使用说明加上demo自己试试看看,在我看来想要了解一件事必须先知道怎么去使用它,之后才是深入了解,解剖实现原理。
目录结果.png

介绍

原始RxJava+Retrofit的请求

正式开始之前我们先看看原始的Retrofit是怎么使用

                //先要构建出okHttpClient
                OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
                okHttpBuilder.readTimeout(10, TimeUnit.SECONDS)
                        .writeTimeout(10,TimeUnit.SECONDS)
                        .connectTimeout(10,TimeUnit.SECONDS)
                        .........省略n多配置

                 OkHttpClient okHttpClient = okHttpBuilder.build();

                //构建出Retrofit实例
                Retrofit.Builder builder = new Retrofit.Builder();
                Retrofit retrofit = builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                        .addConverterFactory(GsonConverterFactory.create())
                        .baseUrl("your_upload_url")
                        .client(okHttpClient)
                        .build();

                retrofit
                        .create(ApiService.class)
                        .getTop250(5)
                        .subscribeOn(Schedulers.io())//请求在IO线程中
                        .observeOn(AndroidSchedulers.mainThread())//回调在主线线程
                        .subscribe(new Observer<Top250Bean>() {
                            @Override
                            public void onSubscribe(@NonNull Disposable d) {
                                
                            }

                            @Override
                            public void onNext(@NonNull Top250Bean top250Bean) {
                                      //请求成功
                            }

                            @Override
                            public void onError(@NonNull Throwable e) {
                                      //请求失败
                            }

                            @Override
                            public void onComplete() {

                            }
                        });

以上就是原始RxJava+Retrofit的请求方式,需要先构建出OKHttpClient,在实例化Retrofit最后才是create并且subscribe,中间还有线程切换的配置,大眼一看一个简单的请求写了这么多代码,这么麻烦,怎么一点也发现不了它的好处呐。别着急,好的东西只要亲身体验过后才知道。

我们总不能每次请求都写这么多代码吧,而且还都是重复的代码,既然是重复的代码我们就能把他抽离出去,进行简单的封装,使用的时候减少不必要的代码量。下边开始介绍如何封装。

封装

步骤 1、封装OkHttpClient 2、封装Retrofit 3、对线程切换的封装 4、对Observer封装

1、首先是要构建一个OkHttpClient,我们就新建一个类单独出来它

public class HttpClient {

    private static HttpClient instance;

    private OkHttpClient.Builder builder;

    public HttpClient() {
        builder = new OkHttpClient.Builder();
    }

    public static HttpClient getInstance() {

        if (instance == null) {
            synchronized (HttpClient.class) {
                if (instance == null) {
                    instance = new HttpClient();
                }
            }

        }
        return instance;
    }


    public OkHttpClient.Builder getBuilder() {
        return builder;
    }

}

以上代码简单到根本需要注释,只是实例化出来okhttpclient,使用builder的方式是为了后边使用的时候方便定制自己的配置。

2、构建出Retrofit,我们也单独新建一个文件处理(代码结果和HttpClient 如出一辙)
public class RetrofitClient {

   private static RetrofitClient instance;

   private Retrofit.Builder mRetrofitBuilder;
   private OkHttpClient.Builder mOkHttpBuilder;

   public RetrofitClient() {

       mOkHttpBuilder = HttpClient.getInstance().getBuilder();

       mRetrofitBuilder = new Retrofit.Builder()
               .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
               .addConverterFactory(GsonConverterFactory.create())
               .client(mOkHttpBuilder.build());
   }


   public static RetrofitClient getInstance() {

       if (instance == null) {
           synchronized (RetrofitClient.class) {
               if (instance == null) {
                   instance = new RetrofitClient();
               }
           }
       }
       return instance;
   }


   public Retrofit.Builder getRetrofitBuilder() {
       return mRetrofitBuilder;
   }

   public Retrofit getRetrofit() {
       return mRetrofitBuilder.client(mOkHttpBuilder.build()).build();
   }

}
3、对线程切换的封装

通过对最原始请求的分析可以看到每次都要对线程切换进行配置,是不是可以把它在进行封装呐,答案肯定是能,这里就要用到RxJava操作符的相关知识了,不了解的可以去搜一下哦,毕竟这样的文章已经有一把大了。
这里我们使用的是compose操作符

public class Transformer {

    /**
     * @param <T> 泛型
     * @return 返回Observable
     */
    public static <T> ObservableTransformer<T, T> switchSchedulers() {
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
                return upstream
                        .subscribeOn(Schedulers.io())
                        .unsubscribeOn(Schedulers.io())
                        .doOnSubscribe(new Consumer<Disposable>() {
                            @Override
                            public void accept(@NonNull Disposable disposable) throws Exception {

                            }
                        })
                        .subscribeOn(AndroidSchedulers.mainThread())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }
}

        //封装之后具体是这样的使用的
        retrofit
                  .......省略部分代码
                  .compose(Transformer.<Top250Bean>switchSchedulers())
4、对Observer的封装
        //原始请求Observer的结果是这样的
        new Observer<Top250Bean>() {
                            @Override
                            public void onSubscribe(@NonNull Disposable d) {

                            }

                            @Override
                            public void onNext(@NonNull Top250Bean top250Bean) {
                                      //请求成功
                            }

                            @Override
                            public void onError(@NonNull Throwable e) {
                                      //请求失败
                            }

                            @Override
                            public void onComplete() {

                            }
                        }

接下来我们对其进行封装,建一个BaseObserver类,继承Observer和ISubscriber,其中ISubscriber是我们提供的一个接口

public interface ISubscriber<T extends BaseResponse> {

    void doOnSubscribe(Disposable d);

    void doOnError(String errorMsg);

    void doOnNext(T t);

    void doOnCompleted();
}

其中我们定义了一个泛型T继承BaseResponse,也许这里你会有疑问,问什么要继承BaseResponse,因为部分请求结果格式都是以下格式

code为错误状态码 ; msg为错误描述信息
        
        {
        code: 0/400/401...,
        msg: 错误描述...,
        ...

        }

这样的格式便于我们对数据统一处理,比如后台规定code=200是请求成功并返回数据,否则就返回msg显示相关错误信息,code=400强制下线,等等自己的一套code规定,遇到这样的我们可以这样在底层统一处理

    @Override
    public void onNext(@NonNull T t) {
        if(t.getCode==200){
               doOnNext(t);
        }else if (t.getCode==400){
            //处理单设备登陆下线的逻辑
        }else{
         showToast(t.getMsg());
        }
       
    }

来看下完整的BaseObserver代码

public abstract class BaseObserver<T extends BaseResponse> implements Observer<T>, ISubscriber<T> {

    private Toast mToast;

    protected void doOnNetError() {
    }

    @Override
    public void onSubscribe(@NonNull Disposable d) {
        doOnSubscribe(d);
    }

    @Override
    public void onNext(@NonNull T t) {
        //这部分因为不同的后台处理逻辑不一样就没直接处理
        //使用者可以根据自己的需求进行定制即可
        doOnNext(t);
    }

    @Override
    public void onError(@NonNull Throwable e) {
        if (e instanceof SocketTimeoutException) {
            setError(ApiException.errorMsg_SocketTimeoutException);
        } else if (e instanceof ConnectException) {
            setError(ApiException.errorMsg_ConnectException);
        } else if (e instanceof UnknownHostException) {
            setError(ApiException.errorMsg_UnknownHostException);
        } else {

            String error = e.getMessage();
            showToast(error);
            doOnError(error);
        }
    }


    @Override
    public void onComplete() {
        doOnCompleted();
    }


    private void setError(String errorMsg) {
        showToast(errorMsg);
        doOnError(errorMsg);
        doOnNetError();
    }


    /**
     * Toast提示
     *
     * @param msg 提示内容
     */
    protected void showToast(String msg) {
        if (mToast == null) {
            mToast = Toast.makeText(BaseRxHttpApplication.getContext(), msg, Toast.LENGTH_SHORT);
        } else {
            mToast.setText(msg);
        }
        mToast.show();
    }

}

如果你不想这个方法返回时候那么多方法,就可以在继承BaseObserver写个CommonObserver做二次处理即可,github代码中已经封装了一个,有需求的可以看下,至此简单的模块封装已经完成了,各个类写好之后需要一个入口去提供方法供外部调用,我们建一个RxHttpUtils类,里边会暴露很多方法,去设置不同参数,前边我们封装的RetrofitClient和HttpClient我们都可以在拿到builder之后进行参数处理了,因为都是些对方法的封装,就不在此贴代码了,需要的可以去看看RxHttpUtils 2.x

5、由于篇幅有限在此对文件下载的进度回调的封装就不做过多说明了,想了解的移步至源码去看看哈

最后来看看我们封装之后的效果吧

                RxHttpUtils
                        .createApi(ApiService.class)
                        .getBook()
                        .compose(Transformer.<BookBean>switchSchedulers(loading_dialog))
                        .subscribe(new CommonObserver<BookBean>(loading_dialog) {
                            @Override
                            protected void getDisposable(Disposable d) {
                                  //用于在onDestroy的时候取消订阅使用
                            }

                            @Override
                            protected void onError(String errorMsg) {
                            }

                            @Override
                            protected void onSuccess(BookBean bookBean) {

                            }
                        });

是不是代码减少很多,看起来更加清爽了

解答疑惑

相信到这里部分人还会有疑惑,为什么不把ApiService和compose也封装进去呐,毕竟网速也有那样去做的,我这里不想对使用者做太多干涉,让使用者自己去创建自己的ApiService,里边的方法名之类的都可以根据自己公司的命名规范去处理,另外使用compose操作符我们可以传一些参数请求的时候显示loading之类的,我代码中已经处理了

以上内容只是对封装的RxHttpUtils 2.x内部实现做了简单的介绍,也有很多功能点没有介绍到位,建议读者结合(RxHttpUtils 2.x)使用说明去进一步了解


系列文章

RXjava+Retrofit 史上最精简封装(RxHttpUtils 1.x)使用说明

RxJava+Retrofit 史上最精简封装(RxHttpUtils 2.x)使用说明

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

推荐阅读更多精彩内容