Android RxJava运算符类似于amb,但仅具有有效结果

Android RxJava运算符类似于amb,但仅具有有效结果,android,rx-java,rx-android,Android,Rx Java,Rx Android,我想在Android应用程序中自动查找设备。因此,我想打两个电话,一个是使用改造的网络电话,另一个是使用自定义SDK的非网络电话,同时找出用户正在使用的设备。应用程序应选择第一个提供有效值的结果 我使用了RxJava并用操作符amb进行了如下尝试: public Observable<LoginResponse> detectDevice(String username, String pwd) { return Observable.amb(device1.login(us

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

我使用了
RxJava
并用操作符
amb
进行了如下尝试:

public Observable<LoginResponse> detectDevice(String username, String pwd) {
    return Observable.amb(device1.login(username, pwd), device2.login(username, pwd));
}
公共可观察检测设备(字符串用户名、字符串密码){
返回Observable.amb(device1.login(用户名,pwd),device2.login(用户名,pwd));
}
如果需要检测的设备是使用网络呼叫的device1,这似乎可以正常工作。但是如果应该检测到的是设备2,它将返回
onError()
,因为
device1.login()
完成得更快,
amb
取第一个
onNext()
onError()
。即使device2.login()提供了一个有效的结果,也不会考虑它,因为它太慢了

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

您可以尝试

Observable.mergeDelayError(device1.login(username, pwd), device2.login(username, pwd)).first()
您可以尝试在
登录
函数的任何输出上使用运算符,查看是否有错误,然后使用运算符以静默方式放弃任何错误:

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();
List logins=new ArrayList();
添加(设备1.login(用户名,pwd));
添加(设备2.login(用户名,pwd));
可观察。来自(登录)
.具体化
.takeUntil((可观察化)->{
return!ObservalEnotification.IsError();
}).非物质化();

一个改进是,如果任何
登录
函数都没有响应,就添加
超时
,向
订户
抛出
可丢弃的
,约翰沃斯邮报启发我使用
物化
,但有一点不同,这就是我的想法:

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
                    }
                }
            }
}
公共可观察检测设备(字符串用户名、字符串密码){
Observable deviceOneObservable=device1.login(用户名、密码)。超时(2,TimeUnit.SECDONDS)。materialize().take(1);
Observable DeviceWoobbservable=device2.login(用户名、密码)。超时(2,TimeUnit.SECONDS)。materialize().take(1);
可观测回波
.zip(deviceOneObservable、DeviceWooObservable、new Func2(){
@凌驾
公用对呼叫(通知登录回复通知,通知登录回复通知2){
返回对。创建(loginResponseNotification,loginResponseNotification 2);
}
})
.flatMap(新函数1(){
@凌驾
公共可观察呼叫(配对notificationNotificationPair){
最终通知设备通知=notificationNotificationPair.first;
最终通知设备WoNotification=notificationNotificationPair.second;
//处理4个不同的设备检测案例
//案例1:未检测到兼容设备
if(DeviceOnNotification.isOnError()&&DeviceWoNotification.isOnError()){
返回可观察的.just(新登录响应(DeviceType.UNKNOWN));
//案例2:检测到设备1
}else if(deviceOneNotification.isOnNext()){
返回可观察的.just(新登录响应(DeviceType.DEVICE_ONE));
//案例3:检测到设备2
}else if(DeviceWoNotification.isOnNext()){
返回可观察的.just(新登录响应(DeviceType.DEVICE_-TWO));
//案例4:发生了错误
}否则{
…//错误处理
}
}
}
}

是您的
设备x.login返回的可观察项吗?有效的单体登录,即它们是否只发出一个项目并终止(或因错误终止)?它们是单体,并返回类型为
LoginResponse
的两个项目。我尝试了您的代码示例,并将可观察项从(登录)更改为可观察项。合并(登录),Observable.from(登录)对我不起作用。但似乎如果一个调用发送一个onError,那么TakeTill并不总是起作用。(登录方法也有其他调用,它们事先启动,例如获取身份验证令牌)