RxJava运算符就像amb,但只有有效的结果

时间:2016-10-17 13:23:08

标签: android rx-java rx-android

我想在Android应用中自动查找设备。因此,我想做两个电话,一个是Retrofit的网络电话和一个使用自定义SDK的非网络电话,同时找出用户正在使用哪个设备。应用程序应选择提供有效值的第一个结果。

我使用RxJava并尝试使用运算符amb,如下所示:

public Observable<LoginResponse> detectDevice(String username, String pwd) {
    return Observable.amb(device1.login(username, pwd), device2.login(username, pwd));
}

如果需要检测的设备是使用网络呼叫的device1,这似乎工作正常。但如果是应该检测到的设备2,它将返回onError(),因为device1.login()完成得更快,amb获得第一个onNext()onError()。尽管device2.login()提供了有效的结果,但它不会被考虑在内,因为它太慢了。

我的问题是:有没有更好的方法来只接受有效的回复或其他运营商?我不想使用zip,因为将来可能会有更多设备,我不想让用户等到每个设备的登录请求完成。

3 个答案:

答案 0 :(得分:2)

您可以尝试在login函数的任何输出上使用materialise运算符并查看它是否有错误,然后使用takeUntil运算符以静默方式丢弃所有错误:

List<Observable<LoginResponse>> logins = new ArrayList<>();
logins.add(device1.login(username, pwd));
logins.add(device2.login(username, pwd));
Observable.from(logins)
    .materialize()
    .takeUntil((observableNotification) -> {
        return !observableNotification.isOnError();
    }).dematerialize();

如果任何timeout函数没有响应将login投放到Throwable,则可以添加Subscriber

答案 1 :(得分:1)

你可以尝试

Observable.mergeDelayError(device1.login(username, pwd), device2.login(username, pwd)).first()

答案 2 :(得分:0)

JohnWowUs的帖子激励我使用materialize,但有点不同,这就是我的用途:

public Observable<LoginResponse> detectDevices(String username, String password) {

    Observable<Notification<LoginResponse>> deviceOneObservable = device1.login(username, password).timeout(2, TimeUnit.SECDONDS).materialize().take(1);
    Observable<Notification<LoginResponse>> deviceTwoObservable = device2.login(username, password).timeout(2, TimeUnit.SECONDS).materialize().take(1);

    return Observable
            .zip(deviceOneObservable, deviceTwoObservable, new Func2<Notification<LoginResponse>, Notification<LoginResponse>, Pair<Notification<LoginResponse>, Notification<LoginResponse>>>() {
                @Override
                public Pair<Notification<LoginResponse>, Notification<LoginResponse>> call(Notification<LoginResponse> loginResponseNotification, Notification<LoginResponse> loginResponseNotification2) {
                    return Pair.create(loginResponseNotification, loginResponseNotification2);
                }
            })
            .flatMap(new Func1<Pair<Notification<LoginResponse>, Notification<LoginResponse>>, Observable<LoginResponse>>() {
                @Override
                public Observable<LoginResponse> call(Pair<Notification<LoginResponse>, Notification<LoginResponse>> notificationNotificationPair) {

                    final Notification<LoginResponse> deviceOneNotification = notificationNotificationPair.first;
                    final Notification<LoginResponse> deviceTwoNotification = notificationNotificationPair.second;

                    //treat 4 different cases of device detection
                    //case1: no compatible device was detected
                    if (deviceOneNotification.isOnError() && deviceTwoNotification.isOnError()) {
                        return Observable.just(new LoginResponse(DeviceType.UNKNOWN));

                        //case2: device1 was detected
                    } else if (deviceOneNotification.isOnNext()) {
                        return Observable.just(new LoginResponse(DeviceType.DEVICE_ONE));

                       //case3:  device2 was detected
                    } else if (deviceTwoNotification.isOnNext()) {
                        return Observable.just(new LoginResponse(DeviceType.DEVICE_TWO));
                       //case4:  error has occurred
                    } else {
                        ... //error handling
                    }
                }
            }
}