写给还不会在项目中使用RxJava的讲解

1,171 阅读6分钟

首先还是强调下,该文如题所示,若已会使用,那可直接略过,返回上一页了。

前言

或许会有人疑问,都什么年代了,还不会 RxJava?em...还真有,这并不关乎能力,很大原因在于环境。特别是一些公司技术要求会比较保守,或者技术负责人没有使用这种技术,那刚出来工作的同学就自然而然地不懂怎么使用了。

由此,对于一些了解 RxJava,却一直不会在项目开发使用的同学,个人希望能够提供一点帮助,让他们能在项目中逐渐使用。毕竟连上手都不懂,更何谈精通。

当然,也有人觉得,网上都这么多优秀的 RxJava 的文章了,为什么还要写着这个?

em...我也清楚写这种文章并不会带来什么浏览量,但是以我学习 RxJava 的过程来说,觉得大部分文章讲解 RxJava 过于纠结于 RxJava 的原理和其操作符,懂 RxJava 的人会觉得,写得很精细,很深入,不错,赞赞赞,但是不懂的人很容易感觉——道理我都懂,但是我就是不知道怎么实际用。

所以,无形中就是有着一面玻璃,懂的人会越来越熟练,不懂的还是原地踏步。

我想做的是打破这玻璃。

扯得有点远了,回归正文。


RxJava说明

按照惯例:

GitHub地址:

github.com/ReactiveX/R…

配置

添加依赖:

    implementation "io.reactivex.rxjava3:rxjava:3.0.11"

简易使用

为了便于讲解,使用的还是 Java。

        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> emitter) throws Throwable {
                Log.e("TAG", "---> subscribe");
                emitter.onNext("");
                emitter.onNext("");
                emitter.onComplete();
            }
        }).subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.e("TAG", "---> onSubscribe");
            }
            @Override
            public void onNext(@NonNull Object o) {
                Log.e("TAG", "---> onNext");
            }
            @Override
            public void onError(Throwable t) {
                Log.e("TAG", "---> onError");
            }
            @Override
            public void onComplete() {
                Log.e("TAG", "---> onComplete");
            }
        });

日志输出:

533-533/com.bjsdm.testrxjava E/TAG: ---> onSubscribe
533-533/com.bjsdm.testrxjava E/TAG: ---> subscribe
533-533/com.bjsdm.testrxjava E/TAG: ---> onNext
533-533/com.bjsdm.testrxjava E/TAG: ---> onNext
533-533/com.bjsdm.testrxjava E/TAG: ---> onComplete

初步讲解

这段代码估计大家都很熟悉了,主要是分为两部分:

  • 创建 Observable 对象,并且调用两次 onNext() 方法,调用一次 onComplete() 方法。
  • 创建 Observer 对象,重写四个方法,并且发现 onNext()、onComplete() 需要被 Observable 主动调用。

OK,我们知道这些就够了,我们看看平常是如何写代码的。

日常代码举例

我们需要实现一个登录功能。

首先,我们需要把登录功能写出一个工具类,并且提供一个 login() 方法进行调用,并且在 login() 方法中传入一个回调,便于访问服务器成功后进行方法回调。

LoginUtil.java

class LoginUtil {
    public void login(String name, String password, HttpCallBack httpCallBack) {
        //模拟网络请求
        SystemClock.sleep(1000);
        if (name.equals("BJSDM") && password.equals("123456")) {
            httpCallBack.success("登录成功");
        } else {
            httpCallBack.error("账号或密码错误");
        }
    }
}

HttpCallBack.java

interface HttpCallBack {
    void success(Object object);
    void error(Object object);
}

调用代码:

        LoginUtil loginUtil = new LoginUtil();
        loginUtil.login("BJSDM", "123456", new HttpCallBack() {
            @Override
            public void success(Object object) {
                Log.e("login success:", object.toString());
            }
            @Override
            public void error(Object object) {
                Log.e("login error:", object.toString());
            }
        });

日志输出:

4064-4064/com.bjsdm.testrxjava E/login success:: 登录成功

代码不难理解,我就不过多说明了,不过,我们倒是可以稍微总结下主要功能:

  • login() 方法调用
  • 回调方法调用
  • 结果展示

日常代码合并到 RxJava

首先,login() 方法无疑是放在subscribe()中,什么?什么是subscribe()

就是这个:

        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> emitter) throws Throwable {
                Log.e("TAG", "---> subscribe");
                emitter.onNext("");
                emitter.onNext("");
                emitter.onComplete();
            }
        })

你看,里面很明显就是业务逻辑处理,可以调用onNext()onComplete(),当然,也还可以调用onError(),如:

emitter.onError(new Throwable("登录异常"));

因此,onNext()onComplete()onError()相当于回调方法,但是,onNext()onComplete()、onError()稍微有些不同,onComplete()、onError()只能调用一次,onNext()可以多次调用,可以这样理解:

  • onComplete():用于表示处理结果的完成。
  • onError():用于标识处理结果异常。
  • onNext():用于业务处理时的数据展示。
  • onSubscribe():用于业务处理。

当然,也可以理解为以下对应关系:

  • onSubscribe()当成login()
  • onComplete()当成success()
  • onError()当成error()

基于上面所讲,我们整理成以下代码:

        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> emitter) throws Throwable {
                //模拟输入
                String name = "BJSDM";
                String password = "123456";
                //模拟网络请求
                SystemClock.sleep(1000);
                if (name.equals("BJSDM") && password.equals("123456")) {
                    emitter.onComplete();
                } else {
                    emitter.onError(new Throwable("账号或密码错误"));
                }
            }
        }).subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
            }
            @Override
            public void onNext(@NonNull Object object) {
            }
            @Override
            public void onError(Throwable t) {
                Log.e("login error:", t.toString());
            }
            @Override
            public void onComplete() {
                Log.e("login success:", "onComplete()");
            }
        });

运行效果:

4686-4686/com.bjsdm.testrxjava E/login success:: onComplete()

方法执行顺序

一看代码量还是挺多的,特别是使用 Java 来看,不过,逻辑就很清晰了。

基本上是以以下顺序进行执行:

  • onSubscribe():执行业务逻辑之前的操作。
  • subscribe():业务逻辑代码。
  • onNext():业务处理时的数据展示。
  • onComplete():功能执行完成。
  • onError():功能执行失败。

虽然以上说法并不够严谨,甚至说不够准确,但是可以先去这样理解顺序,学习上手去实践,等入门了,进阶就有机会了。

并且通过以上的顺序,假如我们想新增功能就很方便了,只要在相应的方法里面填写代码即可,例如我们想新增这样的一个功能:

  • 登录之前把按钮设置为不可点击,
  • 访问网络期间文本设置为“登录中”,
  • 成功或失败后设置为可点击,并且把文本改为“登录”:
Button btnClick = findViewById(R.id.btn_click);
new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                btnClick.setEnabled(false);
            }
            @Override
            public void onNext(@NonNull Object object) {
                btnClick.setText("登录中");
            }
            @Override
            public void onError(Throwable t) {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login error:", t.toString());
            }
            @Override
            public void onComplete() {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login success:", "onComplete()");
            }
        }

完整代码:

        Button btnClick = findViewById(R.id.btn_click);
        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> emitter) throws Throwable {
                //模拟输入
                String name = "BJSDM";
                String password = "123456";
                emitter.onNext("登录中");
                //模拟网络请求
                SystemClock.sleep(1000);
                if (name.equals("BJSDM") && password.equals("123456")) {
                    emitter.onComplete();
                } else {
                    emitter.onError(new Throwable("账号或密码错误"));
                }
            }
        }).subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                btnClick.setEnabled(false);
            }
            @Override
            public void onNext(@NonNull Object object) {
                btnClick.setText("登录中");
            }
            @Override
            public void onError(Throwable t) {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login error:", t.toString());
            }
            @Override
            public void onComplete() {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login success:", "onComplete()");
            }
        });

Observable抽取

由于业务的逻辑处理有时会比较复杂,所以,这是就会把 Observable 和 subscribe 分开进行存放:

LoginUtil.java

class LoginUtil {
    public Observable login(String name, String password) {
        return Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> emitter) throws Throwable {
                emitter.onNext("登录中");
                //模拟网络请求
                SystemClock.sleep(1000);
                if (name.equals("BJSDM") && password.equals("123456")) {
                    emitter.onComplete();
                } else {
                    emitter.onError(new Throwable("账号或密码错误"));
                }
            }
        });
    }
}

业务代码:

        LoginUtil loginUtil = new LoginUtil();
        Button btnClick = findViewById(R.id.btn_click);
        loginUtil.login("BJSDM", "123456").subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                btnClick.setEnabled(false);
            }
            @Override
            public void onNext(@NonNull Object object) {
                btnClick.setText("登录中");
            }
            @Override
            public void onError(Throwable t) {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login error:", t.toString());
            }
            @Override
            public void onComplete() {
                btnClick.setEnabled(true);
                btnClick.setText("登录");
                Log.e("login success:", "onComplete()");
            }
        });

看,是不是跟 Retrofit + RxJava 代码格式很像。

基本上讲到这里,能够看懂,就能在 Demo 上开始实操了,至于各类操作符的使用可以多看看别的文章。

这里,我只负责带入门,仅此而已。