我希望类中的方法在IO线程上运行一些代码,但是只有它们所订阅的Subject具有一定的值。然后,调用方应在Android UI线程上得到响应。
类似这样的东西:
public class MyClass {
private final Subject<Boolean, Boolean> subject;
private final OtherClass otherObject;
public MyClass(Subject<Boolean, Boolean> subject,
OtherClass otherObject) {
this.subject = subject;
this.otherObject = otherObject;
}
public Observable<String> myMethod() {
return waitForTrue(() -> otherObject.readFromDisk());
}
private <T> Observable<T> waitForTrue(Callable<T> callable) {
return subject
.first(value -> value)
.flatMap(value -> Observable.fromCallable(callable))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
这有效吗?不确定,所以我写了一组单元测试来检查它们。我发现我的测试方法尽管在逐个运行时始终有效,但是作为套件的一部分会失败。
事实上,我发现如果我两次进行相同的测试,它将第一次通过,但是第二次失败!
public class MyClassTest {
private TestScheduler ioScheduler;
private TestScheduler androidScheduler;
private TestSubscriber<String> testSubscriber;
private MyClass objectUnderTest;
@Before public void setup() {
ioScheduler = new TestScheduler();
androidScheduler = new TestScheduler();
testSubscriber = new TestSubscriber<>();
RxJavaHooks.reset();
RxJavaHooks.setOnIOScheduler(scheduler -> ioScheduler);
RxAndroidPlugins.getInstance().reset();
RxAndroidPlugins.getInstance().registerSchedulersHook(
new RxAndroidSchedulersHook() {
@Override public Scheduler getMainThreadScheduler() {
return androidScheduler;
};
});
Subject<Boolean, Boolean> subject = BehaviorSubject.create(true);
MyClass.OtherClass otherClass = mock(MyClass.OtherClass.class);
when(otherClass.readFromDisk()).thenReturn("mike");;
objectUnderTest = new MyClass(subject, otherClass);
};
@Test public void firstTest() {
objectUnderTest.myMethod().subscribe(testSubscriber);
ioScheduler.advanceTimeBy(1, TimeUnit.SECONDS);
androidScheduler.advanceTimeBy(1, TimeUnit.SECONDS);
testSubscriber.assertValueCount(1);
// This passes
};
@Test public void secondTest() {
firstTest();
// This fails!
};
}
为什么会这样?并且是测试中的类中的错误还是测试代码?
我认为使用RxJava 1.x可能是个问题,但是我对RxJava 2.x也有类似的问题。
编辑:由于测试代码中缺少一行,因此测试失败。您必须将其放入设置方法中:
AndroidSchedulers.reset()
因为钩子只被AndroidSchedulers
类的静态初始化程序调用一次。
答案 0 :(得分:1)
subscribeOn
对Subject
没有实际影响,因为它们没有订阅副作用,无法迁移到另一个线程。因此,当他们获得新商品时,会在调用者线程上通知其消费者。将项目移动到另一个线程应该通过observeOn
完成:
private <T> Observable<T> waitForTrue(Callable<T> callable) {
return subject
.filter(value -> value)
.take(1)
.observeOn(Schedulers.io())
.map(value -> callable.call())
.observeOn(AndroidSchedulers.mainThread());
}
此外,您不需要flatMap
来执行callable
,映射就足够了。