-->

AndThen executes before completable finished

2019-07-17 02:37发布

问题:

Let's take two methods written with Rx:

Maybe<Foo> getFooFromLocal
Single<Foo> getFooFromNetwork

I want to write a chain when we check our local storage for Foo. If we don't have any Foo we should get it from the network then save it to the local storage and again get it from local storage and pass it to our subscriber.

storage
            .getFooFromLocal()
            .switchIfEmpty(network.getFooFromNetwork().map { it[0] }
                    .flatMapCompletable { storage.saveFoo(it) }
                    .andThen(storage.getFooFromLocal()))
                    .subscriber(/**/)

The problem is that andThen part completes before completable passed into flatMapCompletable. I found out that I can get rid of this problem if I wrap into Maybe.defer{}. But according to the documentation of andThen it

Returns a Maybe which will subscribe to this Completable.

And maybe is already

Represents a deferred computation and emission of a maybe value or exception

So the question is why my andThen part run before completable finished. And what is the best and elegant way to write such chains.

Calls log :

06:05:58.803 getFooFromLocal
06:05:58.804 getFooFromLocal
06:05:58.804 getFooFromNetwork
06:05:59.963 saveFoo

回答1:

This works for me:

public class AndThenTest {

    Integer value;

    @Test
    public void test() {
        getFromLocal()
        .switchIfEmpty(getFromNetwork()
                .flatMapCompletable(v -> saveFoo(v))
                .andThen(getFromLocal()))
        .doOnSuccess(e -> System.out.println("Success: " + e))
        .test()
        .awaitDone(5, TimeUnit.SECONDS)
        .assertResult(10);
    }

    Maybe<Integer> getFromLocal() {
        return Maybe.fromCallable(() -> {
            System.out.println("FromLocal called");
            return value;
        });
    }

    Single<Integer> getFromNetwork() {
        return Single.fromCallable(() -> {
            System.out.println("FromNetwork called");
            return 10;
        }).delay(100, TimeUnit.MILLISECONDS)
                ;
    }

    Completable saveFoo(Integer v) {
        return Completable.fromRunnable(() -> {
            System.out.println("SaveFoo called");
            value = v;
        });
    }
}

and prints:

FromLocal called
FromNetwork called
SaveFoo called
FromLocal called
Success: 10

So my guess is that there is a mistake in one of the methods you are not showing.