RxJava`Completable.then`不是串行执行的吗?
我有一个用例,我在一个完整的表中初始化一些全局变量,然后在链的下一步(使用RxJava`Completable.then`不是串行执行的吗?,java,rx-java,rx-java2,Java,Rx Java,Rx Java2,我有一个用例,我在一个完整的表中初始化一些全局变量,然后在链的下一步(使用和操作符)中使用这些变量 Attempt to read from field 'java.lang.String User.name' on a null object reference 下面的示例详细解释了我的用例 Attempt to read from field 'java.lang.String User.name' on a null object referenc
和操作符)中使用这些变量
Attempt to read from field 'java.lang.String User.name' on a null object reference
下面的示例详细解释了我的用例
Attempt to read from field 'java.lang.String User.name' on a null object reference
假设您有一个classUser
class User {
String name;
}
Attempt to read from field 'java.lang.String User.name' on a null object reference
我有这样一个可观察的
private User mUser; // this is a global variable
public Observable<String> stringObservable() {
return Completable.fromAction(() -> {
mUser = new User();
mUser.name = "Name";
}).andThen(Observable.just(mUser.name));
}
Attempt to read from field 'java.lang.String User.name' on a null object reference
但是当我运行这个代码时,我得到了一个错误
Attempt to read from field 'java.lang.String User.name' on a null object reference
这意味着mUser
为空,然后在执行Completable.fromAction
中的代码之前启动。这里发生了什么事
Attempt to read from field 'java.lang.String User.name' on a null object reference
根据和
Attempt to read from field 'java.lang.String User.name' on a null object reference
返回一个Observable,该Observable将订阅此Completable,一旦完成,则将订阅{@code next}ObservableSource。此Completable中的错误事件将传播到下游订阅服务器,并将导致跳过对Observable的订阅。
Attempt to read from field 'java.lang.String User.name' on a null object reference
问题不在于和,而在于可以观察到的语句。只在于和内部的(mUser.name)
。just
操作符将尝试立即创建可观察对象,尽管它仅在Completable.fromAction
之后才会发出
Attempt to read from field 'java.lang.String User.name' on a null object reference
这里的问题是,在尝试使用just创建可观察的时,mUser
为空
Attempt to read from field 'java.lang.String User.name' on a null object reference
解决方案:您需要推迟创建可观察字符串,直到订阅发生,直到的上游,然后
开始发射
Attempt to read from field 'java.lang.String User.name' on a null object reference
而不是和(Observable.just(mUser.name))代码>
Attempt to read from field 'java.lang.String User.name' on a null object reference
使用
Attempt to read from field 'java.lang.String User.name' on a null object reference
或
Attempt to read from field 'java.lang.String User.name' on a null object reference
我认为@Sarath Kn的答案不是100%正确。是的,just
将在调用后立即创建observable,但然后
仍在意外时间调用just
Attempt to read from field 'java.lang.String User.name' on a null object reference
我们可以将和与flatMap
进行比较,以获得更好的理解。下面是一个完全可运行的测试:
Attempt to read from field 'java.lang.String User.name' on a null object reference
package com.example;
import org.junit.Test;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.Schedulers;
public class ExampleTest {
@Test
public void createsIntermediateObservable_AfterSubscribing() {
Observable<String> coldObservable = getObservableSource()
.flatMap(integer -> getIntermediateObservable())
.subscribeOn(Schedulers.trampoline())
.observeOn(Schedulers.trampoline());
System.out.println("Cold obs created... subscribing");
TestObserver<String> testObserver = coldObservable.test();
testObserver.awaitTerminalEvent();
/*
Resulting logs:
Creating observable source
Cold obs created... subscribing
Emitting 1,2,3
Creating intermediate observable
Creating intermediate observable
Creating intermediate observable
Emitting complete notification
IMPORTANT: see that intermediate observables are created AFTER subscribing
*/
}
@Test
public void createsIntermediateObservable_BeforeSubscribing() {
Observable<String> coldObservable = getCompletableSource()
.andThen(getIntermediateObservable())
.subscribeOn(Schedulers.trampoline())
.observeOn(Schedulers.trampoline());
System.out.println("Cold obs created... subscribing");
TestObserver<String> testObserver = coldObservable.test();
testObserver.awaitTerminalEvent();
/*
Resulting logs:
Creating completable source
Creating intermediate observable
Cold obs created... subscribing
Emitting complete notification
IMPORTANT: see that intermediate observable is created BEFORE subscribing =(
*/
}
private Observable<Integer> getObservableSource() {
System.out.println("Creating observable source");
return Observable.create(emitter -> {
System.out.println("Emitting 1,2,3");
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
System.out.println("Emitting complete notification");
emitter.onComplete();
});
}
private Observable<String> getIntermediateObservable() {
System.out.println("Creating intermediate observable");
return Observable.just("A");
}
private Completable getCompletableSource() {
System.out.println("Creating completable source");
return Completable.create(emitter -> {
System.out.println("Emitting complete notification");
emitter.onComplete();
});
}
}
奇怪的是,,然后
能够在订阅之前创建它的内部可观察性(即调用只是
)。它能做到这一点是有道理的。唯一将要收到的是一个完整的通知,因此没有理由不尽早创建中间可观察对象。唯一的问题是,这不是预期的行为
Attempt to read from field 'java.lang.String User.name' on a null object reference
@Sarath Kn的解决方案是正确的,但原因是错误的。如果我们使用defer
,我们可以看到事情按预期进行:
Attempt to read from field 'java.lang.String User.name' on a null object reference
@Test
public void usingDefer_CreatesIntermediateObservable_AfterSubscribing() {
Observable<String> coldObservable = getCompletableSource()
.andThen(Observable.defer(this::getIntermediateObservable))
.subscribeOn(Schedulers.trampoline())
.observeOn(Schedulers.trampoline());
System.out.println("Cold obs created... subscribing");
TestObserver<String> testObserver = coldObservable.test();
testObserver.awaitTerminalEvent();
/*
Resulting logs:
Creating completable source
Cold obs created... subscribing
Emitting complete notification
Creating intermediate observable
IMPORTANT: see that intermediate observable is created AFTER subscribing =) YEAY!!
*/
}
@测试
在订阅()后,使用Defer\u CreateSinterMediaObservable\u的公共无效{
Observable coldObservable=getCompletableSource()
.然后(Observable.defer(this::getIntermediateObservable))
.subscribeOn(Schedulers.trampoline())
.observeOn(Schedulers.trampoline());
System.out.println(“冷obs创建…订阅”);
TestObserver TestObserver=coldObservable.test();
testObserver.awaitTerminalEvent();
/*
生成的日志:
创建完全源
冷obs已创建…订阅
发出完整通知
创建中间可观察对象
重要提示:请注意,中间可观察对象是在订阅=)之后创建的!!
*/
}
可观察。just(T)
文档声明:“请注意,物品按原样提取和重新发送,而不是just通过任何方式计算。使用fromCallable(Callable)
按需生成单个物品(当观察者订阅时)。”是。答案中也提到了这一点,在答案中直接引用文档是一个很好的答案,但是我认为这个答案是正确的,但是很长。我们需要知道的是,然后
获取一个completable并返回它(或者获取一个并返回它)。如果执行了func1(func2())
,则不会在func1的作用域中调用func2,它将被称为调用者作用域。Sarah将此与关联是错误的。只需。