使用 RxJava2 PublishSubject 管理 null 布尔值

manage null boolean with RxJava2 PublishSubject

我正在实施 MVP 设计模式。我的演示者从视图中接收到新值。我想通过在视图上更新值时自动检查所有内容是否有效来管理下一个按钮的状态。

在我的表单中,我有一个可选部分,只有在用户 select 正确的选项时才会显示。 在这个可选部分中,我有一个二元问题。如果未显示该部分,我需要在 Presenter 端将问题的值设置为 null。 例如,用户 select 显示选项和可选部分。网友select回答。然后用户更改选项,可选部分被隐藏。在那种情况下,我需要将可选问题的答案设置为 null,因为如果用户再次显示可选部分,则答案不会已经 selected。

为此,我使用空值而不是 true/false 在 Presenter 上调用一个方法。

代码如下:

private final PublishSubject<Boolean> mObsOptionalAnswer = PublishSubject.create();

public MyPresenter(){
    // Combine all the values together to enable/disable the next button
    Observable.combineLatest(
        // ... other fields
        // I need this to return false if the optional part is 
        // displayed but nothing is selected
        mObsOptionalAnswer.map(this::isValid),
        (...) -> ...
    ).subscrible(enable ->{
        mView.enableBtn(enable);
    });     
}

public void myFunction(Boolean isSomething){
    // ... some code
    mObsOptionalAnswer.onNext(isSomething);
}

private boolean isValid(Boolean value){
    return value != null;
}

问题是,从 RxJava 2 开始,null 值在 onNext() 方法中是不允许的。 那么,我该如何处理呢?

您可以使用常量布尔对象

 public static final Boolean RESET_VALUE = new Boolean(false);

你可以 emit 这个而不是发出 null。接收方必须检查此实例并相应地进行操作。例如

.subscrible(enable ->{
    if (enable != RESET_VALUE) {
        mView.enableBtn(enable);
    } 
});

如果您希望能够发送空值,可以使用包装器。在此配置中,您发送包装器,即使值本身为 null,它也不是 null。

public class BooleanWrapper {

    public final Boolean value;

    public BooleanWrapper(Boolean value) {
        this.value = value;
    }
}

您的 PublishSubject<Boolean> 变成了 PublishSubject<BooleanWrapper>,您只需创建包装器并在需要时取消引用布尔值即可:

mObsOptionalAnswer.onNext(new BooleanWrapper(isSomething));

mObsOptionalAnswer.map(wrapper -> this.isValid(wrapper.value))

如果您需要在代码中多次这样做,您可以创建一个通用包装器(如 this tutorial 所述):

public class Optional<M> {

    private final M optional;

    public Optional(@Nullable M optional) {
        this.optional = optional;
    }

    public boolean isEmpty() {
        return this.optional == null;
    }

    public M get() {
        return optional;
    }
}