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
假设您有一个class
User

        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将此与
关联是错误的。只需