我有以下设置:
负责更新值的类,该类还提供通过回调侦听此值更改的方法:
private static class ValueUpdater<T> {
Listener<T> listener;
void update(T value) {
if (listener != null) this.listener.onValueUpdated(value);
}
void setListener(Listener<T> listener) {
this.listener = listener;
}
interface Listener<T> {
void onValueUpdated(T value);
}
}
将该类使用的侦听器包装到Observable
:
private static <T> Observable<T> createValueObservable(ValueUpdater<T> valueUpdater) {
return Observable.create(subscriber -> {
valueUpdater.setListener(value -> {
System.out.println("Listener: " + Thread.currentThread().getName());
if (!subscriber.isUnsubscribed()) {
try {
subscriber.onNext(value);
} catch (Exception e) {
subscriber.onError(e);
}
}
});
subscriber.add(Subscriptions.create(() -> valueUpdater.setListener(null)));
});
}
然后像这样调用:
public static void main(String[] args) throws Exception {
final ValueUpdater<Integer> valueUpdater = new ValueUpdater<>();
createValueObservable(valueUpdater)
.subscribeOn(Schedulers.io())
.subscribe(i -> System.out.println("Next: " + Thread.currentThread().getName()));
Thread.sleep(1000);
valueUpdater.update(1);
valueUpdater.update(2);
valueUpdater.update(3);
}
这给了我以下输出:
Listener: main
Next: main
Listener: main
Next: main
Listener: main
Next: main
我知道发生这种情况是因为在主线程上调用ValueUpdater.update()
并导致Observable
在内部切换线程并最终忽略SubscribeOn()
运算符,如{{3 }}
这种情况的最佳替代方案是什么,考虑到我无法修改ValueUpdater
类,我希望能够将Scheduler
应用于上游Observable
?< / p>
编辑:为了让它更清晰一点,我的问题的关键是不明白为什么会这样。我想要了解的是围绕此行为设计代码的最佳方法,防止侦听器回调在主线程上运行。
我想要实现的输出是这样的:
Listener: RxIoScheduler-3
Next: RxIoScheduler-3
Listener: RxIoScheduler-3
Next: RxIoScheduler-3
Listener: RxIoScheduler-3
Next: RxIoScheduler-3
.observeOn()
不会这样做,因为它只会影响下游的项目。如果我要应用它,输出将如下所示:
Listener: main
Listener: main
Listener: main
Next: RxIoScheduler-3
Next: RxIoScheduler-3
Next: RxIoScheduler-3
我尝试使用Observable.fromAsync()
,如下所示,但它也不起作用:
private static <T> Observable<T> createValueObservable(ValueUpdater<T> valueUpdater) {
return Observable.fromAsync(emitter -> {
final CompositeSubscription cs = new CompositeSubscription();
final Scheduler.Worker worker = Schedulers.io().createWorker();
final ValueUpdater.Listener<T> listener = new ValueUpdater.Listener<T>() {
@Override public void onValueUpdated(T value) {
System.out.println("Listener: " + Thread.currentThread().getName());
try {
emitter.onNext(value);
} catch (Exception e) {
emitter.onError(e);
}
}
};
valueUpdater.setListener(listener);
cs.add(worker);
cs.add(Subscriptions.create(() -> valueUpdater.setListener(null)));
emitter.setSubscription(cs);
}, AsyncEmitter.BackpressureMode.BUFFER);
}
我现在能想到的唯一可行解决方案是始终从另一个线程调用ValueUpdater.update()
,但我很确定这对于一个真实的用例是不实际的:
public static void main(String[] args) throws Exception {
final ValueUpdater<Integer> valueUpdater = new ValueUpdater<>();
createValueObservable1(valueUpdater)
.subscribeOn(Schedulers.io())
.subscribe(i -> System.out.println("Next: " + Thread.currentThread().getName()));
Completable.fromAction(() -> {
valueUpdater.update(1);
valueUpdater.update(2);
valueUpdater.update(3);
}).subscribeOn(Schedulers.io()).subscribe();
Thread.sleep(1000);
}
答案 0 :(得分:1)
.subscribeOn()
仅修改订阅.subscribe(...)
发生的位置(我不认为在您的情况下它是必要的,因为您没有io /计算您的订阅)。
您还应该使用.observeOn()
来修改项目处理的位置。
编辑:无论你如何骰子,valueUpdater.update()
的主体都将与调用者在同一个线程中运行。但是,当您立即切换到Rx时,这可能是您正在寻找的内容:
private static <T> Observable<T> createValueObservable(ValueUpdater<T> valueUpdater) {
return Observable.create(subscriber -> {
valueUpdater.setListener(value -> {
if (!subscriber.isUnsubscribed()) {
try {
subscriber.onNext(value);
} catch (Exception e) {
subscriber.onError(e);
}
}
});
subscriber.add(Subscriptions.create(() -> valueUpdater.setListener(null)));
})
.observeOn(Schedulers.io())
.doOnNext(any -> System.out.println("Listener: " + Thread.currentThread().getName()));
}