注
文中用到multicasting这个术语,这个词用得很准确。在网络通讯中mulitcasting这个词表示把数据发给一组特定的目标节点,一般译为多播或者组播。Broadcasting是广播,表示把数据发给网中所有节点。为了保持准确性,下文把multicasting都翻译为多播,如果你觉得用中文读起来有点别扭,可以脑补为广播,可能理解起来更方便。
正文
多播是减少RxJava重复执行的重要方法。
多播一个事件是指,你发送同一个事件给所有下游operators/subscribers。例如做网络请求这种耗时操作时经常这样用,但是我们不希望为每一个subscriber重复执行相同的网络请求,最好只请求一次,然后多播请求结果。
有两个办法实现多播:
- 使用ConnectableObservable (via publish() or replay())
- 使用Subject
任何在ConnectableObservable或者Subject之前的动作都只会被执行一次。然后执行结果被多播给所有下游Subscribers。
这里有一个必须认识到的微妙的地方:多播只在ConnectableObservable或Subject时才发生。同时,多播之后发生的任何动作是为每个Subscriber执行一次。
看个例子:
Observable<String> observable = Observable.just("Event")
.publish()
.autoConnect(2)
.map(s -> {
System.out.println("Expensive operation for " + s);
return s;
});
observable.subscribe(s -> System.out.println("Sub1 got: " + s));
observable.subscribe(s -> System.out.println("Sub2 got: " + s));
// Output:
// Expensive operation for Event
// Sub1 got: Event
// Expensive operation for Event
// Sub2 got: Event
代码中有ConnectableObservable,一个耗时的map()操作和两个订阅者。
这里有个问题,即使我们添加了publish()来避免重复执行,那个耗时的map()还是被执行了两次,这是我们不期望的。具体流程如下图:
如果希望map()只执行一次,应该把它放在publish()之前调用:
Observable<String> observable = Observable.just("Event")
.map(s -> {
System.out.println("Expensive operation for " + s);
return s;
}) .publish()
.autoConnect(2);
observable.subscribe(s -> System.out.println("Sub1 got: " + s));
observable.subscribe(s -> System.out.println("Sub2 got: " + s));
// Output:
// Expensive operation for Event
// Sub1 received: Event
// Sub2 received: Event
更新后的流程如下:
这告诉我们什么呢?如果你想用多播减少不必要的开销,一定要在正确的位置做多播。
不论好坏,很多人都在使用Subject。它的一大优点是多播,但是你必须要清楚,它们只在他们发出的时候多播。如果你有一批耗时操作要发布给下游的Subject,那你就需要考虑给下游的什么地方添加一个publish()。
.