RxJava 与 Retrofit 搭配的链式调用

准备工作

导入相关的依赖库,不要忘记导入 RxAndroid 的库

// 开头的两个是两个适配器的依赖,根据自己的需求加,官网还有更多适配器的选择
implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'

使用场景分析

在平时的安卓开发中,我们遇到像注册和登录这两个网络请求的时候,有时候会有这样的需求,我注册完了就紧接着要登录,通常遇到这钟情况的时候,我们都会选择在注册请求的回调当中接着去登录,这样子感觉还可以接受,只会有一层的嵌套,但是如果连续的请求更多的时候,就会在写代码的时候发现嵌套的层次太多了,代码的逻辑不容易读懂。
这个时候如果我们使用的是 Rxjava 的时候,就会发现一连串的逻辑从头写到尾,思路十分的清楚,代码也很好读,当然 Rxjava 本身还是需要大家花一定得时间去学习,在这里我推荐一个大神的教程,看他的教程再搭配自己的使用的话就会很有收获,大神博客,他把 Observable 和 Observer 比喻为水管,形容的很贴切,对没有学过 Rxjava1 的人也很友好。

先上代码

public interface LoginInterface {

    @GET("***")
    Call<LoginBean> login(@Query("StudentID") String studentId, @Query("Password") String password, @Query("**") String param1, @Query("**") String param2);
        
    @GET("***")
    Observable<WeixinConnectBean> getUserInfo(@Query("StudentID") String studentId, @Query("**") String param1, @Query("**") String param2);

}
Retrofit retrofit = new Retrofit.Builder()
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    // 换成你自己的URL
                    .baseUrl("********************")
                    .build();
LoginInterface mLoginInterface = retrofit.create(LoginInterface.class);

上面的这些代码和我们直接使用 Retrofit 来进行网络请求没有任何区别,但是 Retrofit 可以和 Rxjava 搭配进行网络请求,当然这里还忘了介绍 Rxjava 的另一个优点,就是线程切换十分方便,可以在下面的代码里面体现出来,让我们接着看下面的代码。

            mLoginInterface
                    .login_1(studentId, password, String.valueOf(currentTime), md5Str.substring(3, 18).toUpperCase())
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnNext(new Consumer<LoginBean>() {
                        @Override
                        public void accept(LoginBean loginBean) throws Exception {

                            if (loginBean.getCode() != 1) {
                                AlertDialog builder = new AlertDialog.Builder(LoginActivity.this)
                                .setMessage(loginBean.getMsg())
                                .setTitle("提示!")
                                .setPositiveButton("我知道了", null)
                                .create();
                                builder.show();
                                dialog.cancel();
                                loginButton.setClickable(true);
                            }
                            Log.d(TAG, "登录成功!");
                            Log.d(TAG, "" + loginBean.getCode());

                        }
                    })
                    .doOnError(new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {

                            loginButton.setClickable(true);
                            Log.d(TAG, "调用失败");

                        }
                    })
                    .observeOn(Schedulers.io())
                    .flatMap(new Function<LoginBean, Observable<WeixinConnectBean>>() {
                        @Override
                        public Observable<WeixinConnectBean> apply(LoginBean loginBean) throws Exception {

                           if (loginBean.getCode() != 1) {
                               mDisposable.dispose();
                           }

                           long currentTime = System.currentTimeMillis();
                           String md5Str = Md5Util.md5(KEY + currentTime);
                           return mLoginInterface.getUserInfo(studentId, String.valueOf(currentTime), md5Str.substring(3, 18).toUpperCase());

                        }
                    })
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<WeixinConnectBean>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            mDisposable = d;
                        }

                        @Override
                        public void onNext(WeixinConnectBean response) {

                            getCourseData(studentId, password);
                            progressAnimator.start();

                            loginButton.setClickable(true);

                            String userName = response.getStuName();
                            String major = response.getMajor();
                            SharePreferenceLab.getInstance().setUsername(LoginActivity.this, userName);
                            SharePreferenceLab.getInstance().setMajor(LoginActivity.this, major);

                        }

                        @Override
                        public void onError(Throwable e) {

                            Log.d(TAG, "调用失败");
                            Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                            dialog.cancel();
                            loginButton.setClickable(true);


                        }

                        @Override
                        public void onComplete() {

                        }
                    });

大家可能第一反应会觉得代码不是很简洁,甚至有点不好理解,但是但凡大家对 Rxjava 有一定的掌握,都会觉得这样写很容易理解,特别是链接的请求更加多的时候,优势越发明显。

链式请求的难点

我觉得链式请求最需要注意的两个点一个是操作符的使用,另一个就是中断请求。我们接下来来分析这两个点。

FlatMap 操作符的使用

在这种情况下我们选择使用 Rxjava 的 FlatMap 操作符,这样子我们就可以将上一个请求返回的结果转换成下一个请求,这样就可以接着进行下一个请求了,根据上面的例子,我们需要实现一个 Function<LoginBean, Observable<WeixinConnectBean>>() 这个类里的 apply 这个方法,最后返回的一个 Observable,也就是另一个请求,在这里我们返回的是 mLoginInterface.getUserInfo(studentId, String.valueOf(currentTime), md5Str.substring(3, 18).toUpperCase()) ,当然这里还要注意一点,之前我们切换了线程到了主线程,这里我们需要回到 io 线程进行网络请求,但是这里还是用的是 observeOn 来切换线程。

中断请求

这里我们就要用 Rxjava 里面的一个新的东西叫作 Disposable,我们通过它来中止请求,这一点在我之前那个大神介绍的文章里面介绍的很仔细,他在里面比喻说相当于切断了上下游的联系,但是我们在哪里获取的 Disposable 的呢,大家看最后面的代码会发现,我们在订阅的时候,会先调用 onSubscribe 这个方法,这个方法的参数里面会给我们一个 Disposable 的引用,我们持着这个引用在需要中断的时候调用 dispose 方法,就会中止请求。

总结

当然 Rxjava 的操作符远不止这么一些,在以后还是会结合使用场景来进行分析,相信使用多了就会了解 Rxjava 的便利性。

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

推荐阅读更多精彩内容