RxJava的设计原理以及在项目中的实际应用

目的

  相信做过Android开发的同学都在项目中使用过Rxjava这个库,它可以化繁为简,让代码更简洁、更清晰。这篇文章我将简要介绍RxJava的基本原理以及在项目中使用到的一些常用功能。当然,对于RxJava如何使用并不是本文讨论的重点,我主要想由此及彼,探讨我们在碰到一些优秀的三方库的时候,应该怎样去学习,去使用,能够让我们个人的专业技能有所提高。

基本原理

定义

RxJava官网是这样介绍的:

RxJava:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
翻译:RxJava 是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库

原理
  • RxJava: 基于 一种扩展的观察者模式
  • RxJava的扩展观察者模式中有4个角色:
角色 作用
被观察者(Observable) 产生事件
观察者(Observer) 接收事件,并给出响应动作
订阅(Subscribe) 连接 被观察者 & 观察者, 相当于注册监听
事件(Event) 被观察者 & 观察者 沟通的载体
  • 使用
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onComplete();
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, "accept integer = " + integer);
                    }
                });
  • 说明:上面的使用很简单,链式结构,有种一气呵成的感觉,看起来很舒服,其实做了很多事情
  1. 创建被观察者,发送事件,即emitter.onNext(1),发送了数字1;
  2. 指定被观察者的执行线程,Schedulers.io();
  3. 观察者处理接收到的数据;
  4. 切换线程到主线程,观察者将在主线程处理这些数据。
  • 总结
  1. RxJava一个核心功能就是线程切换,可以看到,使用简单,代码看起来很简洁、明了;
  2. 链式结构,很熟悉吧,平时我们创建Dialog的时候,就是链接结构;

在项目中的实际应用

  所有的库都是以项目的实际需求为导向,如果在项目中没法使用,那这个库就没任何意义了。RxJava也是如此,之所以有这么多人使用,就是因为项目里面很多操作,不管是简单的还是复杂的操作,都可以使用RxJava很简洁的实现,当然,前提是你要熟悉RxJava。
  可能大家会有疑问,前面介绍的使用很简单,没什么精彩的地方,不管怎么看,也不像能在项目中大量的使用。是的,如果只是这样,确实没有什么值得推崇的。RxJava强大的地方,不仅在于线程切换的方便,更重要的是,它有非常多的操作符,可以实现项目中比较复杂的操作。关于这些操作符的详细解读,可以阅读我专门写的一篇文章:操作符全解

下面列举一些在项目中使用很多的用例:

1. 功能防抖
  • 使用Rxjava很简单,这里可以防止用户点击登录按钮过快,打开多个登录页面的问题
        RxView.clicks(layoutLogin)
                .throttleFirst(1, TimeUnit.SECONDS)
                .subscribe(new Consumer<Unit>() {
                    @Override
                    public void accept(Unit unit) throws Exception {
                        
                    }
                });
2. 定时器
  • 蓝牙项目使用,延时500ms处理一些事务
        Observable.timer(500, TimeUnit.MILLISECONDS)
             .subscribeOn(Schedulers.io())
             .subscribe(new Consumer<ArrayList<XmBluetoothDeviceInfo>>() {
            @Override
            public void accept(ArrayList<XmBluetoothDeviceInfo> xmBluetoothDeviceInfos) throws Exception {
                DialogManager.getInstance().askForDismiss(dialogController, true);
                if (ObjectUtils.isNotEmpty(xmBluetoothDeviceInfos)) {
                    startDeviceDetails(edrDevice, xmBluetoothDeviceInfos);
                } else {
                    ToastUtils.showShort(StringUtils.getString(R.string.xm_data_error));
                    finish();
                }
            }
        })
3.监听器
  • 在项目中使用最多,替代了以前我们通过Listener的方式处理监听,这里的好处很多:调用方便;线程切换简单;不用处理添加和删除时的同步问题等等
    private final PublishSubject mPublishSubject = PublishSubject.create();
    public Disposable registerSessionEvent(Consumer<SessionEvent> onNext) {
        Disposable disposable = mPublishSubject.observeOn(AndroidSchedulers.mainThread()).subscribe(onNext);
        mCompositeDisposable.add(disposable);
        return disposable;
    }
4.连续点击N次,每次间隔M毫秒。两个操作符搞定,如果自己写的话就比较复杂了。
        mCompositeDisposable.add(observable.buffer(observable.debounce(300, TimeUnit.MILLISECONDS))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(units -> {
                    if (units != null && units.size() >= 5) {
                        mTestConfigBtn.setVisibility(View.VISIBLE);
                        DebugConfig.enableDebug();
                    }
                }));
5. RxBus
  • 事件总线,可直接代替EventBus、广播的使用,在项目中也是使用的非常多
        val d = RxBus.getInstance().register(ChangeBgEvent::class.java)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { changeBgEvent -> activity.setTitleColor(changeBgEvent.color) }

  以上只是项目中使用到的列举的很少一部分,实际用到了很多。可以看到,它确实用简洁的代码实现了比较复杂的功能,提升了开发效率。

我们应该如何学习

  既然三方库能够给我们的开发带来很大的效率提升,我们当然推荐使用。但是如何使用却是值得探讨,是不是只要会用就行了呢?个人觉得绝对不能只是简单的知道它的用法就行,我们不仅要知其然,还要知其所以然,这样才能理解它的原理,使用起来更加得心应手,不至于使用出错,在碰到问题的时候解决起来也更加顺利。
下面是我对于学习使用三方库的一些看法:

熟练基本用法
  • 这是最基本的要求。一般三方库都会有使用文档,我们可以通读一遍,也可以在网上看别人写的一些文章,学习别人对于一些用法的理解。
学习源码

  这个比较关键,也是个人比较推荐的做法,我们只有看懂了源码,才能理解它的原理,并学习它的一些优秀的框架和设计

  1. 注释
  • 源码里面有对代码的详细解释,还有使用用例,看这些注释加深对接口的理解,有些注释,看一遍就知道使用使用了
 * Example usage:
 * <pre> {@code

  PublishSubject<Object> subject = PublishSubject.create();
  // observer1 will receive all onNext and onComplete events
  subject.subscribe(observer1);
  subject.onNext("one");
  subject.onNext("two");
  // observer2 will only receive "three" and onComplete
  subject.subscribe(observer2);
  subject.onNext("three");
  subject.onComplete();

  // late Observers only receive the terminal event
  subject.test().assertEmpty();
  } </pre>
  1. 装饰者模式
  • 库里面大量用到了装饰者模式,这是RxJava的核心,也是我们能够很简洁使用的关键。
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {

    /** The source consumable Observable. */
    protected final ObservableSource<T> source;

    /**
     * Constructs the ObservableSource with the given consumable.
     * @param source the consumable Observable
     */
    AbstractObservableWithUpstream(ObservableSource<T> source) {
        this.source = source;
    }

    @Override
    public final ObservableSource<T> source() {
        return source;
    }

}
  1. 链式结构
  • Rxjava的使用通过链式结构直接完成,简洁明了,对我们平时的代码设计有很好的借鉴意义,下面是蓝牙的同事使用的案例,实现了比较复杂的逻辑(省略了具体实现)
        Disposable subscribe = getMaybe(bluetoothDeviceExt)
                .map(new Function<TargetResponseWrap, XmHistoryDeviceInfo>() {
                    @Override
                    public XmHistoryDeviceInfo apply(TargetResponseWrap targetResponseWrap) throws Exception {
                        ......
                    }
                })
                .map(new Function<XmHistoryDeviceInfo, XmBluetoothDeviceInfo>() {
                    @Override
                    public XmBluetoothDeviceInfo apply(XmHistoryDeviceInfo xmHistoryDeviceInfo) throws Exception {
                        ......
                    }
                })
                .flatMap(new Function<XmBluetoothDeviceInfo, MaybeSource<XmBluetoothDeviceInfo>>() {
                    @Override
                    public MaybeSource<XmBluetoothDeviceInfo> apply(final XmBluetoothDeviceInfo deviceInfo) throws Exception {
                        ......
                    }
                })
                .doOnSuccess(new Consumer<XmBluetoothDeviceInfo>() {
                    @Override
                    public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
                        ......
                    }
                })
                .doOnSuccess(new Consumer<XmBluetoothDeviceInfo>() {
                    @Override
                    public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
                        ......
                    }
                })
                .flatMap(new Function<XmBluetoothDeviceInfo, MaybeSource<XmBluetoothDeviceInfo>>() {
                    @Override
                    public MaybeSource<XmBluetoothDeviceInfo> apply(final XmBluetoothDeviceInfo deviceInfo) throws Exception {
                        ......
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<XmBluetoothDeviceInfo>() {
                    @Override
                    public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
                        ......
                    }
                });

  当然,RxJava里面还有很多值得开发者学习的地方。如果不能理解充分,很可能会误用,在引入项目初期,也有一些使用不当的地方,包括我自己,后面熟悉之后就好多了。

分享总结
  • 我们经常说,完成一件事情或任务,要学会总结,这样才能更加深刻。对于我们软件开发者而言也是一样的,学习之后,能够分享,能够总结,其好处不言而喻。

  以上是我在项目中使用Rxjava的一些介绍和使用心得。以及由此引出的引入三方库之后,我们应该如何使用和学习的一些粗浅看法。一句话,就是在引入一个库后,能够学习它背后的原理。

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

推荐阅读更多精彩内容