RxJava2的Observable变种之四大热发射

在关于Observable变种之五大金刚一文分析中,我们知道Observable在收到Observer订阅的时候,就会立即发送数据,既为冷发射。而热发射既只是为Observable和Observer之间建立了订阅管道,并不会直接发射数据,而是在有需要的时候才发射数据。而热发射的场景就有很多了,因为热发射我们可以决定发射时机、地点、数据。

四大热发射集成自抽象Subject,而Subject集继承自Observable,同时还实现了Observer,因此实际既可以作为Observable,还可以作为Observer。既然四大热发射都继承自Observable,所以订阅仍然形如Observable.subscribe(observer), 订阅之后仍然具体走到subscribeActual具体方法中,因此本文将四大热发射称为Observable的变种。

PublishSubject——接收订阅之后的所有数据

PublishSubject<String> publish = PublishSubject.create();
publish.subscribe(new PublishObserver<String>("first"));
publish.onNext("1");
publish.onNext("2");
publish.subscribe(new PublishObserver<String>("seconde"));
publish.onNext("3");
publish.onCompleted();

如上例子,则第一个订阅的观察者将收到1、2、3数据,而第二个订阅的观察者只收到3的数据。此处,在PublishSubject中有一个保存订阅者的属性,是个数组,可以通过分析代码知道,当发送数据后,就会遍历这个数组的订阅者,发射数据到各个订阅者中。

final AtomicReference<PublishSubject.PublishDisposable<T>[]> subscribers;

BehaviorSubject——释放订阅前最后一个数据和订阅后的所有数据

BehaviorSubject<String> behavior = BehaviorSubject.create("deafault");
behavior.subscribe(new SubjectObserver<String>("first"));
behavior.onNext("1");
behavior.onNext("2");
behavior.subscribe(new SubjectObserver<String>("seconde"));
behavior.onNext("3");
behavior.onCompleted();

上面例子中,第一个订阅者讲收到包括default在内的1、2、3数据,而第二个订阅将收到订阅前的最后一条数据2,后面的所有数据3。那么BehaviorSubject是怎么收到在订阅前的最后一条数据的呢?如下

protected void subscribeActual(Observer<? super T> observer) {
    BehaviorSubject.BehaviorDisposable<T> bs = new BehaviorSubject.BehaviorDisposable(observer, this);
    observer.onSubscribe(bs);
    if (this.add(bs)) {
        if (bs.cancelled) {
            this.remove(bs);
        } else {
            bs.emitFirst();
        }
    } else {
        Throwable ex = (Throwable)this.terminalEvent.get();
        if (ex == ExceptionHelper.TERMINATED) {
            observer.onComplete();
        } else {
            observer.onError(ex);
        }
    }

}

订阅时进入到我们熟悉的subscribeActual方法,然后进入bs.emitFirst()中,如下:

void emitFirst() {
    if (!this.cancelled) {
        Object o;
        synchronized(this) {
            if (this.cancelled) {
                return;
            }

            if (this.next) {
                return;
            }

            BehaviorSubject<T> s = this.state;
            Lock lock = s.readLock;
            lock.lock();
            this.index = s.index;
            o = s.value.get();
            lock.unlock();
            this.emitting = o != null;
            this.next = true;
        }

        if (o != null) {
            if (this.test(o)) {
                return;
            }

            this.emitLoop();
        }

    }
}

主要看this.test(o),此时如果上次有发射,则o为相关发射。

ReplaySubject——将所有接收到的数据或通知全部发送给订阅者

ReplaySubject<String> replay = ReplaySubject.create();
replay.subscribe(new SubjectObserver<String>("first"));
replay.onNext("1");
replay.onNext("2");
replay.subscribe(new SubjectObserver<String>("seconde"));
replay.onNext("3");
replay.onCompleted();

上面例子中,第一个订阅者将收到1、2、3和complete通知,第二个订阅者也是收到1、2、3和complete通知。

protected void subscribeActual(Observer<? super T> observer) {
    ReplaySubject.ReplayDisposable<T> rs = new ReplaySubject.ReplayDisposable(observer, this);
    observer.onSubscribe(rs);
    if (!rs.cancelled) {
        if (this.add(rs) && rs.cancelled) {
            this.remove(rs);
            return;
        }

        this.buffer.replay(rs);
    }
}

订阅之后,进入subscribeActual方法,this.buffer为SizeAndTimeBoundReplayBuffer的实例。走到this.buffer.replay(rs)中,进入到下面代码:

public void replay(ReplaySubject.ReplayDisposable<T> rs) {
    if (rs.getAndIncrement() == 0) {
        int missed = 1;
        Observer<? super T> a = rs.actual;
        ReplaySubject.TimedNode<Object> index = (ReplaySubject.TimedNode)rs.index;
        if (index == null) {
            index = this.getHead();
        }

        while(!rs.cancelled) {
            while(!rs.cancelled) {
                ReplaySubject.TimedNode<Object> n = (ReplaySubject.TimedNode)index.get();
                if (n == null) {
                    if (index.get() == null) {
                        rs.index = index;
                        missed = rs.addAndGet(-missed);
                        if (missed == 0) {
                            return;
                        }
                    }
                } else {
                    Object o = n.value;
                    if (this.done && n.get() == null) {
                        if (NotificationLite.isComplete(o)) {
                            a.onComplete();
                        } else {
                            a.onError(NotificationLite.getError(o));
                        }

                        rs.index = null;
                        rs.cancelled = true;
                        return;
                    }

                    a.onNext(o);
                    index = n;
                }
            }

            rs.index = null;
            return;
        }

        rs.index = null;
    }
}

上面代码既是为啥在订阅个第二个订阅者的时候,会响应收到数据1、2。这里大概分析一下,我们看到,ReplaySubject主要维护了一个ReplaySubject.TimedNode链表,凡是发射过的都会进入到这个链表中保存,因此通过遍历这个链表,然后发个后来的订阅者。

AsyncSubject——当发送onComplete才会发送最后一条数据

AsyncSubject async = AsyncSubject.create();
async.subscribe(new SubjectObserver<String>("first"));
async.onNext("1");
async.onNext("2");
async.onNext("3");
async.onCompleted();
async.subscribe(new SubjectObserver<String>("seconde"));
async.onCompleted();

上面例子中,第一个订阅者发送了3个数据,只有送到onCompleted的时候,订阅者才接受最后一条数据3,同样的,第二个订阅者订阅之后,就直接发送onCompleted,那么第二订阅者也同样收到数据3.

具体分析如下:发送onNext的时候,会保存当前数据到属性value中,这个value后面用到。

public void onNext(T t) {
    ObjectHelper.requireNonNull(t, "onNext called with null. Null values are generally not allowed in 2.x operators and sources.");
    if (this.subscribers.get() != TERMINATED) {
        this.value = t;
    }
}

当发送onComplete的时候,代码如下:

public void onComplete() {
    if (this.subscribers.get() != TERMINATED) {
        T v = this.value;
        AsyncSubject.AsyncDisposable<T>[] array = (AsyncSubject.AsyncDisposable[])this.subscribers.getAndSet(TERMINATED);
        AsyncSubject.AsyncDisposable[] var3;
        int var4;
        int var5;
        AsyncSubject.AsyncDisposable as;
        if (v == null) {
            var3 = array;
            var4 = array.length;

            for(var5 = 0; var5 < var4; ++var5) {
                as = var3[var5];
                as.onComplete();
            }
        } else {
            var3 = array;
            var4 = array.length;

            for(var5 = 0; var5 < var4; ++var5) {
                as = var3[var5];
                as.complete(v);
            }
        }

    }
}

则当value不为空的时候,遍历订阅者数组,从而调用as.complete(v),as为DeferredScalarDisposable实例,complete的具体实现如下:

public final void complete(T value) {
    int state = this.get();
    if ((state & 54) == 0) {
        if (state == 8) {
            this.value = value;
            this.lazySet(16);
        } else {
            this.lazySet(2);
        }

        Observer<? super T> a = this.actual;
        a.onNext(value);
        if (this.get() != 4) {
            a.onComplete();
        }

    }
}

从而调用订阅者的onNext方法,输出相关的数据。

通过上面的分析,我们知道,热发射相对冷发射提供了很多方便,它并不会要求订阅者订阅之后就要马上接收数据,相反的,根据需要,在特定的场景下进行相关的数据的发射,使得我们更加灵活运用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值