【从零学 RxJava】RxJava 1 Hot Observable & Cold Observable、Subject

前言

什么是 RxJava

RxJavaRxJava 上的实现,用于通过使用 Observable/Flowable 序列来构建异步和基于事件的程序的库

什么是 Rx

RxReactiveXReactive Extensions,是一种编程模式,目标是提供一致的编程接口,帮助开发者更方便地处理异步数据流。Rx 库几乎支持所有地编程语言没比如 .NET JavaScript C++ Java

本章节介绍 Hot Observable & Cold Observable 相关概念和 API 示例

版本

3.0.4

基础概念

Observable

被观察者,使用 RxJava 时需要创建一个被观察者,用于发送事件,类比于 设计模式:观察者模式 的被观察者

Hot Observable

Hot Observable 无论有没有 观察者 进行订阅,事件始终都会发生,一个 Hot Obsevable 可以对应多个 订阅者

Hot Observable 可以类比于 广播电台

Cold Observable

Cold Observable 是只有 观察者 订阅了,才开始发射数据,Cold ObservableObserver 是一一对应的

Cold Observable 可类比于 仅供个人欣赏的CD

Observer

观察者,可以在不同的线程中执行任务,而不需要阻塞,响应 Observable 的通知,同样类比于 设计模式:观察者模式 的观察者

subscribe

动作,订阅,连接 ObservableObserver

Subject

Subject 既是 Observable,又是 Oberver,官网称可以将 Subject 看作一个桥梁或者代理

API 示例

GAV

	<dependency>
	    <groupId>io.reactivex.rxjava3</groupId>
	    <artifactId>rxjava</artifactId>
	    <version>3.0.4</version>
	</dependency>

hello world

第一步,从 hello world 直观的认识 RxJava 的编程模式

	public static void main(String[] args) {

        Observable.just("hello world")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Throwable {
                        System.out.println(s);
                    }
                });

        // Lambda 
        // Observable.just("hello world").subscribe(t -> System.out.println(t));

        /**
         * subscribe 的重载
         * Observable#subscribe(Consumer onNext, Consumer onError, Action onComplete)
         */
        Observable.just("hello world 2")
                .subscribe(
                        // onNext
                        new Consumer<String>() {
                            @Override
                            public void accept(String s) throws Throwable {
                                System.out.println(s);
                            }
                        }
                        // onError
                        , new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Throwable {
                                System.out.println("error");
                            }
                        }
                        // onComplete
                        , new Action() {
                            @Override
                            public void run() throws Throwable {
                                System.out.println("onComplete");
                            }
                        }
                );

        // Lambda 
        /*Observable.just("test2")
                .subscribe(
                        t -> System.out.println(t)
                        , e -> System.out.println("error")
                        , () -> System.out.println("complete")
                );*/
    }

此处,Observable#just 方法创建一个发射简单字符串的 Observable,匿名 Consumer 订阅该信息并输出 hello world

借助 Lambda 表达式会更加简洁优雅

同样,其 重载方法 支持多种回调,如 onNext onError onComplete

do 操作符

可以控制 Observable 的生命周期

	public static void main(String[] args) {
        Observable.just("test")
                // 每发射一条数据就会被调用一次,在 subscribe 发生
                .doOnNext(t -> System.out.println("doOnNtext " + t))
                // 在 Consumer#onNext 之后调用
                .doAfterNext(t -> System.out.println("doAfterNext " + t))
                // 在 Observable 正常终止时调用
                .doOnComplete(() -> System.out.println("doOnComplete"))
                // 一旦被订阅,就会被调用,返回 Disposable
                .doOnSubscribe(d -> System.out.println("doOnSubscribe " + d.isDisposed()))
                // 当 Observable 调用 onComplete 或 onError 会调用,在 doFinally 之后
                .doAfterTerminate(() -> System.out.println("doAfterTerminate"))
                // 当 Observable 调用 onComplete 或 onError 会调用
                .doFinally(() -> System.out.println("doFinally"))
                // 当 Observable 每发射一项数据,都会调用一次,返回 Notification
                .doOnEach(n -> System.out.println("doOnEach "
                        + (n.isOnNext() ? "onNext" : n.isOnComplete() ? "onComplete" : "onError")))
                // 在订阅之后,返回 Disposable,可以设置是否取消订阅
                .doOnLifecycle(
                        d -> System.out.println("doOnLifecycle " + d.isDisposed())
                        , () -> System.out.println("doOnLifecycle action"))
                .subscribe(t -> System.out.println(t));
    }

	// 结果
	doOnSubscribe false
	doOnLifecycle false
	doOnNtext test
	doOnEach onNext
	test
	doAfterNext test
	doOnComplete
	doOnEach onComplete
	doFinally
	doAfterTerminate

具体 生命周期 的触发时机见代码注释

Hot Observable & Cold Observable

Observablejust create 等操作符生成的都是 Cold Observable,比如示例中的 Observable#just,同样它可以转换成 Hot Observable

Cold Observable

	static void coldObservable() throws InterruptedException {
        Observable o = Observable.create(e -> {
            Observable.interval(
                    10
                    , TimeUnit.MILLISECONDS
                    , Schedulers.computation()
            )
                    .take(Integer.MAX_VALUE)
                    .subscribe(e::onNext);
        })
                .observeOn(Schedulers.newThread());

        o.subscribe(t -> System.out.println("c1: " + t));
        o.subscribe(t -> System.out.println("   c2: " + t));

        Thread.sleep(200);
    }

	// 结果:
	c1: 0
	   c2: 0
	   c2: 1
	c1: 1
	   c2: 2
	c1: 2
	   c2: 3
	   c2: 4
	c1: 3
	c1: 4
	   c2: 5
	c1: 5
	   c2: 6
	   c2: 7
	c1: 6
	c1: 7
	   c2: 8
	c1: 8
	c1: 9
	c1: 10
	   c2: 9
	   c2: 10

可以看到,c1c2 的结果完全独立

c2h

	static void c2h() throws InterruptedException {
        Observable o = Observable.create(e -> {
            Observable.interval(
                    10
                    , TimeUnit.MILLISECONDS
                    , Schedulers.computation()
            )
                    .take(Integer.MAX_VALUE)
                    .subscribe(e::onNext);
        })
                .observeOn(Schedulers.newThread());

        // publish 操作符,将 Cold Observable 转化为 Hot Observable
        ConnectableObservable connectableObservable
                = o.publish();
        // 需要调用 connect 才开始执行
        connectableObservable.connect();

        connectableObservable.subscribe(t -> System.out.println("c1: " + t));
        connectableObservable.subscribe(t -> System.out.println("   c2: " + t));

        Thread.sleep(100);

        connectableObservable.subscribe(t -> System.out.println("       c3: " + t));

        Thread.sleep(100);
    }

	// 结果:
	c1: 0
	   c2: 0
	c1: 1
	   c2: 1
	c1: 2
	   c2: 2
	c1: 3
	   c2: 3
	c1: 4
	   c2: 4
	c1: 5
	   c2: 5
	c1: 6
	   c2: 6
	c1: 7
	   c2: 7
	c1: 8
	   c2: 8
	c1: 9
	   c2: 9
	c1: 10
	   c2: 10
	c1: 11
	   c2: 11
	       c3: 11
	c1: 12
	   c2: 12
	       c3: 12
	c1: 13
	   c2: 13
	       c3: 13
	c1: 14
	   c2: 14
	       c3: 14
	c1: 15
	   c2: 15
	       c3: 15
	c1: 16
	   c2: 16
	       c3: 16
	c1: 17
	   c2: 17
	       c3: 17
	c1: 18
	   c2: 18
	       c3: 18
	c1: 19
	   c2: 19
	       c3: 19
	c1: 20
	   c2: 20
	       c3: 20
	c1: 21
	   c2: 21
	       c3: 21

通过 publish 操作符,Cold Observable 可以转化为 Hot Observable,可以看到实例中的 订阅者 共享一个 Observablec3 丢失了订阅之前的消息(广播电台不会因为你没打开收音机而为你补上之前的消息)

h2c

	static void h2c() throws InterruptedException {
        ConnectableObservable connectableObservable
                = Observable.create(e -> {
            Observable.interval(
                    10
                    , TimeUnit.MILLISECONDS
                    , Schedulers.computation()
            )
                    .take(Integer.MAX_VALUE)
                    .subscribe(e::onNext);
        })
                .observeOn(Schedulers.newThread())
                .publish();

        connectableObservable.connect();

        Observable o = connectableObservable.refCount();

        /**
         * Disposable:可以选择是否取消订阅
         */
        Disposable d1 = o.subscribe(t -> System.out.println("c1: " + t));
        Disposable d2 = o.subscribe(t -> System.out.println("   c2: " + t));

        Thread.sleep(20);

        /**
         * 取消订阅
         */
        d1.dispose();
        d2.dispose();

        System.out.println("重新发送");
        o.subscribe(t -> System.out.println("c1: " + t));
        o.subscribe(t -> System.out.println("   c2: " + t));

        Thread.sleep(20);
    }

	// 结果:
	c1: 0
	   c2: 0
	c1: 1
	   c2: 1
	c1: 2
	   c2: 2
	重新发送
	c1: 0
	   c2: 0
	c1: 1
	   c2: 1
	c1: 2
	   c2: 2

通过 refCount 操作符,Hot Observable 可以转化为 Cold Observable

同时,如果所有 订阅者 取消订阅,则数据流停止,重新订阅则开始重新发送。注意,是所有 订阅者 取消订阅,如果仅部分 订阅者 取消,则重新订阅并不会重新发送,如下示例:

	static void h2c2() throws InterruptedException {
        ConnectableObservable connectableObservable
                = Observable.create(e -> {
            Observable.interval(
                    10
                    , TimeUnit.MILLISECONDS
                    , Schedulers.computation()
            )
                    .take(Integer.MAX_VALUE)
                    .subscribe(e::onNext);
        })
                .observeOn(Schedulers.newThread())
                .publish();

        connectableObservable.connect();

        Observable o = connectableObservable.refCount();

        /**
         * Disposable:可以选择是否取消订阅
         */
        Disposable d1 = o.subscribe(t -> System.out.println("c1: " + t));
        Disposable d2 = o.subscribe(t -> System.out.println("   c2: " + t));

        Thread.sleep(20);

        /**
         * 仅 d1 取消订阅
         */
        d1.dispose();
        // d2.dispose();

        System.out.println("重新发送");
        o.subscribe(t -> System.out.println("c1: " + t));

        Thread.sleep(20);
    }

	// 结果:
	c1: 0
	   c2: 0
	c1: 1
	   c2: 1
	c1: 2
	   c2: 2
	重新发送
	   c2: 3
	c1: 3
	   c2: 4
	c1: 4
	   c2: 5
	c1: 5

可以看到,因为 c2 并没有取消订阅,因此重新订阅后的 Observable 没有重新发送数据

Subject

Subject 有四种类型

AsyncSubject

Observer 会接受 AsyncSubjectonComplete 之前的最后一个数据

	static void asyncSubject() {
        AsyncSubject asyncSubject = AsyncSubject.create();

        asyncSubject.onNext(1);
        asyncSubject.onNext(2);

        asyncSubject.subscribe(t -> System.out.println(t));

        asyncSubject.onNext(3);
        asyncSubject.onNext(4);
        asyncSubject.onComplete();
    }

	// 4

BehaviorSubject

Observer 会先接收到 BehaviorSubject 被订阅之前的最后一个数据,在接受订阅之后发射的数据。如果被订阅之前没有发送任何数据,则会发送一个默认数据

	static void behaviorSubject() {
        BehaviorSubject behaviorSubject
                = BehaviorSubject.createDefault("default");

        // behaviorSubject.onNext(1);

        behaviorSubject.subscribe(t -> System.out.println(t));

        behaviorSubject.onNext(2);
    }
	
	// default 2

如果打开注释的代码,则结果为 1 2,订阅前未发射数据则 Observer 接受到默认消息 default

ReplaySubject

ReplaySubject 可以发射所有来自原始 Observable 的数据,也可以选择只缓存订阅前的若干条消息,乃至缓存多长时间

	// 发射所有消息
    static void replaySubject1() {
        ReplaySubject replaySubject = ReplaySubject.create();

        replaySubject.onNext(1);
        replaySubject.onNext(2);

        replaySubject.subscribe(t -> System.out.println(t));

        replaySubject.onNext(3);
    }

	// 1 2 3

    // 缓存一条消息
    static void replaySubject2() {
        ReplaySubject replaySubject = ReplaySubject.createWithSize(1);

        replaySubject.onNext(1);
        replaySubject.onNext(2);

        replaySubject.subscribe(t -> System.out.println(t));

        replaySubject.onNext(3);
    }

	// 2 3

    // 缓存 1s
    static void replaySubject3() throws InterruptedException {
        ReplaySubject replaySubject
                = ReplaySubject.createWithTime(
                        1
                        , TimeUnit.SECONDS
                        , Schedulers.newThread()
                );

        replaySubject.onNext(1);

        Thread.sleep(2000);

        replaySubject.subscribe(t -> System.out.println(t));

        replaySubject.onNext(3);
    }

	// 3

PublishSubject

Observer 只接受 PublishSubject 被订阅之后的数据

	static void publishSubject() {
        PublishSubject publishSubject = PublishSubject.create();

        publishSubject.onNext(1);
        publishSubject.onNext(2);

        publishSubject.subscribe(t -> System.out.println(t));

        publishSubject.onNext(3);
        publishSubject.onNext(4);
    }

	// 3 4

总结

本章节介绍 Hot Observable & Cold ObservableSubject 相关概念以及 API,下一章节介绍 RxJava操作符

下一篇:【从零学 RxJava】RxJava 2 —— 创建操作符

github

文中涉及的示例 demo

https://github.com/dangzhicairang/rxjava.git

参考

RxJava 2.x 实战 —— 沈哲

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值