我是RxJava的新手,并试图确定常见的习语和最佳做法。
说我已经有Foo
课程发出Bar
s(目前不完整且过于简化):
class Foo {
public Subscriber barSubscriber;
public Observable<Bar> getBarObservable = (...details omitted...)
private void someMethod() {
// emit a Bar
barSubscriber.onNext(bar);
}
}
想要订阅Bars
的其他对象通过调用
foo.getBarObservable().subscribe(...);
让我们说生产和发出Bar
是昂贵的&#34;。为了避免在没有订阅者的情况下执行此操作,Foo的getBarObservable
可以公开一个可连接的,重新计算的Observable
,如此(使用share()
):
class Foo {
private Subscriber barSubscriber;
private Observable<Bar> barObservable = Observable.create(
new Observable.OnSubscribe<Bar>() {
@Override
public void call(Subscriber<? super Bar> subscriber) {
Foo.this.subscriber = subscriber;
new Thread(new Runnable() {
@Override
public void run() {
runUntilUnsubscribed();
}
}).start();
}
}
).share();
public Observable<Bar> getBarObservable() {
return barObservable;
}
public void runUntilUnsubscribed(} {
while(!subscriber.isUnsubscribed()) {
/* do some heavy stuff that produces a Bar. If, when a
Bar is ready, we still have subscribers, emit the Bar */
if (!subscriber.isUnsubscribed())
subscriber.onNext(bar);
}
}
}
我见过的大多数示例和教程都会在订阅它们的相同代码块中即时创建Observable
内联,所以我不清楚它是什么标准做法是在更真实的场景中,Observable
的创建及其订阅位于两个不同的地方。
Foo
这样一个不想知道订阅者是谁或者会有多少订阅者的类,这是正确的方法吗?Observable
的正确方法吗?常规使用这种方法有缺点吗?if (subscriber == null && !subscriber.isUnsubscribed())
subscriber.onNext(bar);
时,我都需要那个小Bar
模式。这也是一个常见的习语,还是有更好的方法?答案 0 :(得分:3)
是的,这大致是正确的做法。如果bar
中的Foo
需要与所有订阅者共享,请使用.publish().refCount()
(或share()
,如您所说)。如果没有,那么使用一个常见的Observable,默认情况下是“冷”。
公开Observable是一种常见的情况。在一个良好的反应式架构中,大多数类只有Observables的getter,因为setter本身不具有反应性。给定一个与setter一起使用的程序或类,通常可以将它转换为Observables和getter而不影响功能。由于一些控制反转,可观测量和吸气剂是一种理想的方法。使用setter,如果Foo
在Baz
中设置了值,则只要您想了解Foo
,就需要查看课程Baz
。但是对于Observables和getters,Baz
来自Foo
而Baz
定义了它的工作原理,而Foo
可以忽略Baz
。
我从未需要使用if
模式。我也很少需要Observable.create()
。有许多Observable创建助手(from
,interval
,range
,just
,仅举几例)和Observable转换(例如全能{{1} })允许你在表达新的Observables方面取得很大进展。此外,主题允许您在旅途中手动创建Observable。
答案 1 :(得分:3)
您的示例类无法正常工作:如果订阅者为setBar
,则null
可以抛出NPE,runUntilUnsubscribed
引用缺少的bar字段/值,并且是繁忙的循环将反复发出相同的值。
你说创建一个Bar
是昂贵的,但它的创建似乎超出了Foo
类,我想你想要将这样的价值发送给当前订阅的订阅者。这就是PublishSubject的用途:
class Foo {
final PublishSubject<Bar> subject = PublishSubject.create();
public void setBar(Bar bar) {
subject.onNext(bar);
}
public Observable<Bar> getBarObservable() {
return subject; // .asObservable() if you want to hide the subject
}
}
如果没有任何订阅者,那么条形图集就会掉线并收集垃圾。如果您想保留最后一个值,请使用BehaviorSubject
代替PublishSubject
。
否则,如果您需要在订阅者到达时触发创建昂贵的Bar值,您可以使用share()
的一些跳转启动序列:
Observable.just(1)
.subscribeOn(Schedulers.computation())
.map(v -> createBar())
.share();
但share()
的使用实际上取决于每个Bar值的预期生命周期。
例如,如果您希望存储条形码直到订阅者到达,然后执行繁重的计算并分发结果,您可以使用以下构造:
class Foo {
final BehaviorSubject<Bar> subject = BehaviorSubject.create();
final Observable<Bar> output = subject
.observeOn(Schedulers.computation())
.doOnNext(bar -> expensiveInplaceComputation(bar))
.take(1)
.share();
public void setBar(Bar bar) {
subject.onNext(bar);
}
public Observable<Bar> getBarObservable() {
return output;
}
}
有关可运行的示例,请参阅this gist。