RxJava2表单验证

sou*_*rar 8 validation android rx-java2

我有一个表格,有4个可能的选项需要检查(根据情况可能会更少).在创建订单时,有2个editexts,一个用于电子邮件,另一个用于参考字段.

电子邮件和参考字段可能会根据条件(在创建表单时可用)保留为空.此外,我们可能需要显示一个警告对话框,告诉用户可能无法显示参考值(对订单的收件人),他们可能还需要同意条款和条件警报对话框.

目前onConfirm检查是这样的,

void onCreateOrderConfirmed(@Nullable final String receiverEmail,
                            @Nullable final String reference,
                            @Nullable final Boolean noRefAgreed,
                            @Nullable final Boolean termsAndConditionsAgreed) {

    if (!reviewCompletionState.emailRequirementSatisfied()) {
        if (!isValidEmail(receiverEmail)) {
            view.showEmailError();
            return;
        }

        reviewCompletionState = reviewCompletionState.newBuilder()
                .receiverEmail(receiverEmail)
                .emailRequirementSatisfied(true)
                .build();
    }

    if (!reviewCompletionState.referenceRequirementSatisfied()) {
        if (isEmpty(reference)) {
            view.showReferenceError();
            return;
        }

        reviewCompletionState = reviewCompletionState.newBuilder()
                .reference(reference)
                .referenceRequirementSatisfied(true)
                .build();
    }

    if (!reviewCompletionState.noRefAgreed()) {
        if (noRefAgreed == null || !noRefAgreed) {
            view.showNoReferenceAlert();
            return;
        }

        reviewCompletionState = reviewCompletionState.newBuilder()
                .noRefAgreed(true)
                .build();
    }

    if (!reviewCompletionState.termsAndConditionsAgreed()) {
        if (termsAndConditionsAgreed == null || !termsAndConditionsAgreed) {
            view.showTermsDisclaimerAlert();
            return;
        }

        reviewCompletionState = reviewCompletionState.newBuilder()
                .termsAndConditionsAgreed(true)
                .build();
    }

    createOrder();
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有办法使用RxJava2简化这个验证?(但目前还不知道能够做到这一点)

TIA

Anr*_*ian 5

这可能很简单。将有很多代码,我将首先显示结果。

    private ReviewValidator reviewValidator = new ReviewValidator();

    void onCreateOrderConfirmed(@Nullable final String receiverEmail,
                                @Nullable final String reference,
                                @Nullable final Boolean noRefAgreed,
                                @Nullable final Boolean termsAndConditionsAgreed) {
        ReviewState reviewState = new ReviewState(receiverEmail,
                reference,
                noRefAgreed,
                termsAndConditionsAgreed);//another model for simplicity

        reviewValidator.validate(reviewState)
                .flatMap(reviewState -> /* create order */)
                .subscribe(this::onOrderCreated, this::onOrderCreatingError);

    }

    void onOrderCreated(Object order) {//or what you need here
        //handle positive result
    }

    void onOrderCreatingError(Throwable throwable) {
        if (throwable instanceof ValidateException) {
            List<ValidateError> errors = ((ValidateException) throwable).getValidateErrors();
            for (ValidateError error: errors) {
                switch (error.getField()) {
                    case EMAIL: {
                        view.showEmailError();
                        return;//or break if you want show all errors
                    }
                    case REFERENCE: {
                        view.showReferenceError();
                        return;
                    }
                    //handle another errors....
                }
            }
        //handle another error cases...
    }
Run Code Online (Sandbox Code Playgroud)

首先,为reviewState创建模型:

public class ReviewState {

    private String receiverEmail;
    private String reference;
    private Boolean noRefAgreed;
    private Boolean termsAndConditionsAgree;

    public ReviewState(String receiverEmail,
                       String reference,
                       Boolean noRefAgreed,
                       Boolean termsAndConditionsAgree) {
        this.receiverEmail = receiverEmail;
        this.reference = reference;
        this.noRefAgreed = noRefAgreed;
        this.termsAndConditionsAgree = termsAndConditionsAgree;
    }

    public String getReceiverEmail() {
        return receiverEmail;
    }

    public String getReference() {
        return reference;
    }

    public Boolean getNoRefAgreed() {
        return noRefAgreed;
    }

    public Boolean getTermsAndConditionsAgree() {
        return termsAndConditionsAgree;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后创建您自己的验证器。不必创建整个模型,可以为每个字段创建验证器,然后将其与您选择的flatMap()链接。

public class ReviewValidator extends Validator<ReviewState> {

    @Override
    protected List<ValidateFunction> getValidateFunctions(ReviewState reviewState) {
        List<ValidateFunction> validateFunctions = new LinkedList<>();
        validateFunctions.add(() -> validateEmail(reviewState.getReceiverEmail()));
        validateFunctions.add(() -> validateReference(reviewState.getReference()));
        //another validation methods
        return validateFunctions;
    }

    private ValidateError validateEmail(String email) {
        if (TextUtils.isEmpty(email)) {
            return new ValidateError(Field.EMAIL);//Field.EMAIL - just enum
        }
        return null;
    }


    private ValidateError validateReference(String reference) {
        if (TextUtils.isEmpty(reference)) {
            return new ValidateError(Field.REFERENCE);
        }
        return null;
    }
    //....
    //another validation methods
}
Run Code Online (Sandbox Code Playgroud)

验证器的抽象类:

public abstract class Validator<Model> {

    public Single<Model> validate(Model model) {
        return Single.just(model)
                .map(this::validateModel)
                .flatMap(this::processResult);
    }

    private Single<Model> processResult(ValidateResultModel<Model> validateResultModel) {
        return Single.create(subscriber -> {
            List<ValidateError> validateErrors = validateResultModel.getValidateErrors();
            if (validateErrors.isEmpty()) {
                subscriber.onSuccess(validateResultModel.getModel());
            } else {
                subscriber.onError(new ValidateException(validateErrors));
            }
        });
    }

    private ValidateResultModel<Model> validateModel(Model model) {
        List<ValidateError> errors = new LinkedList<>();
        for (ValidateFunction validateFunctions : getValidateFunctions(model)) {
            ValidateError error = validateFunctions.validate();
            if (error != null) {
                errors.add(error);
            }
        }
        return new ValidateResultModel<>(model, errors);
    }

    protected abstract List<ValidateFunction> getValidateFunctions(Model model);

    protected interface ValidateFunction {

        @Nullable
        ValidateError validate();
    }
}
Run Code Online (Sandbox Code Playgroud)

验证程序的帮助程序类...

public class ValidateError {

    private Field field;

    public ValidateError(Field field) {
        this.field = field;
    }

    public Field getField() {
        return field;
    }
}

class ValidateResultModel<T> {

    private T model;
    private List<ValidateError> validateErrors;

    ValidateResultModel(T model, List<ValidateError> validateErrors) {
        this.model = model;
        this.validateErrors = validateErrors;
    }

    T getModel() {
        return model;
    }

    List<ValidateError> getValidateErrors() {
        return validateErrors;
    }
}

public class ValidateException extends RuntimeException {

    private List<ValidateError> validateErrors;

    ValidateException(List<ValidateError> validateErrors) {
        this.validateErrors = validateErrors;
    }

    public List<ValidateError> getValidateErrors() {
        return validateErrors;
    }
}
Run Code Online (Sandbox Code Playgroud)

最初,我从这里接受了这个想法:https : //github.com/matzuk/TestableCodeMobius/tree/master/app/src/main/java/com/matsyuk/testablecodemobius/business/transfer/validation


Bob*_*owo 3

我认为你应该 RxJava CoupleLatest,所以你需要所有的表单输入都生成一个可观察的,然后你只需将它组合起来并调整视图

作为参考,您可以检查:

https://medium.com/@etiennelawlor/rxjava-on-the-sign-in-screen-9ecb66b88572

使用 RxJava 进行电子邮件登录验证,可观察对象发出两次

========

例子:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxCompoundButton;
import com.jakewharton.rxbinding2.widget.RxTextView;

import io.reactivex.Observable;


public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    EditText receiverText = findViewById(R.id.input_receiver);
    EditText referenceText = findViewById(R.id.input_reference);
    CheckBox checkRef = findViewById(R.id.check_ref);
    CheckBox checkTerms = findViewById(R.id.check_terms);
    Button buttonLogin = findViewById(R.id.button_login);

    Observable<CharSequence> receiverObservable = RxTextView.textChanges(receiverText).skip(1); // can add more logic
    Observable<CharSequence> referenceObservable = RxTextView.textChanges(referenceText).skip(1); // can add more logic
    Observable<Boolean> refCheckObservable = RxCompoundButton.checkedChanges(checkRef); // can add more logic
    Observable<Boolean> termsCheckObservable = RxCompoundButton.checkedChanges(checkTerms); // can add more logic

    Observable<String> combineObservable = Observable.combineLatest(
            receiverObservable,
            referenceObservable,
            refCheckObservable,
            termsCheckObservable, (receiverCharSequence, referenceCharSequence, refBoolean, termsBoolean) -> {
                // add logic here for now it is only combine the input
                return  receiverCharSequence + " " + referenceCharSequence + " " + refBoolean + " " + termsBoolean ;}
            );

    RxView.clicks(buttonLogin).flatMap(o -> { return combineObservable;}).distinctUntilChanged().subscribe(string -> {
        Toast.makeText(this, string, Toast.LENGTH_LONG).show();
    });

    }
}
Run Code Online (Sandbox Code Playgroud)