RxJava将两种不同类型的可观察对象组合成第三种类型的可观察对象

时间:2016-09-02 15:04:24

标签: android rx-java

我有两个服务器端点。 端点1采用用户名和密码并返回一个id。 端点2接受一个并返回UserProfile对象。

我尝试编写一个方法,该方法将用户名和密码作为参数并返回Observable<User>(其中User是由一个字段组成的对象,该字段是来自端点1的id和另一个字段作为UserProfile)。

我已经弄清楚如何调用我的第一个端点并使用结果id作为第二个端点的输入,但是我仍然坚持如何使用来自第二个端点的响应以及来自第二个端点的响应第一个创建User对象并返回它的端点。

这不是正确的,但它是我能够进步最远的:

    public Observable<UserProfile> login(String u, String p) {
        return mNetworkApi.establishSessionViaCreds(u, p)
            .flatMap(s -> mNetworkApi.getUserProfile(s));
    }

此方法接受两个字符串并输出Observable<UserProfile>。我需要它输出一个Observable。可以通过获取第一个observable(String)的输出和第二个observable(UserProfile)的输出来创建用户。但是我该怎么办呢?下面是我想要的方法签名,但没有正确的代码来创建Observable。

public Observable<User> login(String username, String password) {
    mNetworkApi.doLogin(username, password)
        flatMap((Func1<String, Observable<?>>) s -> mNetworkApi.getUserProfile(s));
    /..Code to transform observable.../
    return ...;
}

有没有办法可以从具有两种不同类型(String和UserProfile)的observable创建一个带有第三种类型(User)的Observable?

EDIT 为了解释这个问题,我做得更好。第一个observable返回一个字符串。该字符串用作下一个observable的输入,但是在第二个observable运行之后,我需要从第一个observable访问该字符串,并且不再能够获得对它的引用。

EDIT 这是我能得到的尽可能接近,但由于“id”而且仍然无法工作。无法进入。如果我可以获得对id的引用,那么这将完美地工作但我调用新的User(id,userProfile),id变量是不可访问的。

    @Override
public Observable<User> loginUser(String username, String password) {
    Observable<String> observableUsername = Observable.just(username);
    Observable<String> observablePassword = Observable.just(password);

    Observable<User> userObs = Observable.zip(observableUsername, observablePassword,
            (user, pass) ->
                mNetworkApi.establishSessionViaCreds(user, pass)
                    .flatMap(id -> mNetworkApi.getUserProfile(id))
                        .map(userProfile -> new User(id, userProfile))
    ).flatMap(new Func1<User, Observable<?>>() {
        @Override
        public Observable<?> call(User user) {
            return Observable.just(new User(id, userProfile));
        }
    });

    return userObs;
}

修改

Observable<User> userObs = Observable.zip(observableUsername, observablePassword,
            (user, pass) ->
                    mNetworkApi.establishSessionViaCreds(user, pass)
                            .flatMap(id -> mNetworkApi.getUserProfile(id)
                                    .map(new Func1<UserProfile, User>() {
                                        @Override
                                        public User call(UserProfile userProfile) {
                                            return Observable.just(new User(id, userProfile));
                                        }
                                    })
                            )
    );

2 个答案:

答案 0 :(得分:1)

flatMap的覆盖允许您指定Func2来合并原始输入和Func1的输出。对于你的情况,它看起来像:

public Observable<User> login(String u, String p) {

    return networkApi
            .establishSessionViaCreds(u, p)
            .flatMap(
                    // here is the normal Func1
                    new Func1<String, Observable<UserProfile>>() {
                        @Override
                        public Observable<UserProfile> call(String id) {
                            return networkApi.getUserProfile(id);
                        }
                    },
                    // here is the extra Func2 which allows the merge
                    new Func2<String, UserProfile, User>() {
                        @Override
                        public User call(String id, UserProfile userProfile) {
                            return new User(id, userProfile);
                        }
                    }
            );
}

或者如果你正在使用lambdas:

public Observable<User> login(String u, String p) {

    return networkApi
            .establishSessionViaCreds(u, p)
            .flatMap(
                    id -> { return networkApi.getUserProfile(id); },
                    User::new
            );
}

答案 1 :(得分:0)

您需要Observable.zip

Observable<String> username = ...;
Observable<String> password = ...;

Observable<User> userObs = Observable.zip(username, password,
  (user,pass) ->
    mNetworkApi.doLogin(user, pass)
               .flatMap(id -> mNetworkApi.getUserProfile(id))
)
.flatMap(obs -> obs);

请注意,最后一行是必需的,因为zip是A + B -> C,但在这种情况下我们正在执行A + B -> Observable<C>,我们需要解压缩生成的Observable。