RxJava:减少不按预期工作

时间:2017-01-02 18:29:21

标签: java java-ee rx-java reactive-programming

我试图并行加载用户对象。

    final User user = new User();
    final Observable<User> userObs = Observable.just("NAMES", "ADDRESSES", "CURRENT_ADDRESS")
            .flatMap(field -> getOrchestrator(user, field))
            .scan(new User(), (finalUser, event) -> {
                finalUser = event;
                return finalUser;
            });

扫描确实会发出三个用户对象,因为reduce根本不会发出任何项目?我在这做错了什么。

    final User user = new User();
    final Observable<User> userObs = Observable.just("NAMES", "ADDRESSES", "CURRENT_ADDRESS")
            .flatMap(field -> getOrchestrator(user, field))
            .reduce(new User(), (finalUser, event) -> {
                finalUser = event;
                return finalUser;
            });

getOrchestrator返回Observable。任何帮助将不胜感激。

以下是完整的代码段

public class Orchestrator {
    private String userId;

    public Orchestrator(final String userId) {
        this.userId = userId;
    }

    public static void main(final String[] args) throws Exception {
        final User user = new User();
        final Observable<User> userObs = Observable.just("NAMES", "ADDRESSES", "CURRENT_ADDRESS")
                .flatMap(field -> getOrchestrator(user, field))
                .scan(new User(), (finalUser, event) -> {
                    finalUser = event;
                    return finalUser;
                });

        userObs.subscribeOn(Schedulers.io()).subscribe(result -> {
            System.out.println(result.toString());
        });

        TimeUnit.SECONDS.sleep(10);

    }

    private static Observable<User> getOrchestrator(final User user, final String fieldName) {
        switch (fieldName) {
            case "CURRENT_ADDRESS":
                return new AddressOrchestrator().getCurrentAddress(user.getUserId())
                        .map(currentAddress -> {
                            user.setAddress(currentAddress);
                            try {
                                TimeUnit.MILLISECONDS.sleep(200);
                            }
                            catch (final InterruptedException e) {

                            }
                            return user;
                        });
            case "ADDRESSES":
                return new AddressOrchestrator().getAddresses(user.getUserId())
                        .map(addresses -> {
                            user.setAddresses(addresses);
                            try {
                                TimeUnit.MILLISECONDS.sleep(200);
                            }
                            catch (final InterruptedException e) {

                            }
                            return user;
                        });

            case "NAMES":
                return new NameOrchestrator().getNames(user.getUserId())
                        .map(names -> {
                            user.setNames(names);
                            try {
                                TimeUnit.MILLISECONDS.sleep(200);
                            }
                            catch (final InterruptedException e) {

                            }
                            return user;
                        });
        }
        return null;
    }

    public User getUser() {
        final Random r = new Random();
        if (r.nextInt(3) % 2 == 0) {
            return new User();
        }
        throw new RuntimeException();
    }
}

每个orchestrator都返回Observable。

public class AddressOrchestrator {

    public Observable<List<Address>> getAddresses(final String userId) {
        return Observable.create(s -> {
            final Address currentAddress = this.getBaseAddress(userId);
            final Address anotherAddress = this.getBaseAddress(userId);
            anotherAddress.setState("NE");
            s.onNext(Arrays.asList(currentAddress, anotherAddress));
        });

    }

    public Observable<Address> getCurrentAddress(final String userId) {
        return Observable.create(s -> s.onNext(this.getBaseAddress(userId)));
    }

    public Address getBaseAddress(final String userId) {
        final Address address = new Address();
        address.setLine1("540 Caddo Lake Dr");
        address.setCity("Georgetown");
        address.setCountry("USA");
        address.setState("TX");

        return address;
    }
}


public class NameOrchestrator {

    public Observable<List<Name>> getNames(final String userId) {
        return Observable.create(s -> {
            final Name name = new Name();
            name.setName("Vanchi");
            final Name formerName = new Name();
            formerName.setName("Vanchinathan");
            s.onNext(Arrays.asList(name, formerName));
        });
    }
}

2 个答案:

答案 0 :(得分:3)

您使用Observable.create创建的编排(除非您真正知道自己正在做什么,否则一个大红旗)不会终止。这会导致无限的流(从某种意义上说,永远不会发出完整的事件)。你需要什么呢

public Observable<List<Address>> getAddresses(final String userId) {
        return Observable.create(s -> {
            final Address currentAddress = this.getBaseAddress(userId);
            final Address anotherAddress = this.getBaseAddress(userId);
            anotherAddress.setState("NE");
            s.onNext(Arrays.asList(currentAddress, anotherAddress));
            s.onCompleted();
        });

注意被调用的onCompleted。这将解决您的表面问题,但您最好先摆脱Observable.create并使用Observable.defer之类的东西。

答案 1 :(得分:1)

这种情况正在发生,因为scan会发出所有上游项,而reduce只会在流完成后才会发出。

替换

public Observable<Address> getCurrentAddress(final String userId) {
    return Observable.create(s -> s.onNext(this.getBaseAddress(userId)));
}

public Observable<Address> getCurrentAddress(final String userId) {
    return Observable.fromCallable(() -> this.getBaseAddress(userId));
}

public Observable<List<Address>> getAddresses(final String userId) {
    return Observable.create(s -> {
        final Address currentAddress = this.getBaseAddress(userId);
        final Address anotherAddress = this.getBaseAddress(userId);
        anotherAddress.setState("NE");
        s.onNext(Arrays.asList(currentAddress, anotherAddress));
    });
}

public Observable<List<Address>> getAddresses(final String userId) {
    return Observable.fromCallable(() -> this.getBaseAddress(userId))
            .zipWith(Observable.fromCallable(() -> this.getBaseAddress(userId))
                    .map(address -> address.setState("NE")),
                    (currentAddress, anotherAddress) -> Arrays.asList(currentAddress, anotherAddress));
}

并将您的setAddress()方法更改为此

public Address setState(String state) {
    this.state = state;
    return this;
}

fromCallable()是创建最多只发出一个元素的Observable的更好方法,因为它会为您处理错误和背压。