我有一个表格,其中有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();
}
我很想知道是否有办法使用RxJava2简化此验证? (但目前还不知道能够做到这一点)
TIA
答案 0 :(得分:5)
这可能很简单。会有很多代码,我会先显示结果。
ruby -run -ehttpd . -p9001
首先,为reviewState创建模型:
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...
}
然后创建自己的验证器。没有必要创建一个完整的模型,你可以为每个字段创建验证器,并将它们与你选择的flatMap()链接起来。
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;
}
}
验证器的抽象类:
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
}
验证器的助手类......
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();
}
}
最初,我从这里接受了这个想法:https://github.com/matzuk/TestableCodeMobius/tree/master/app/src/main/java/com/matsyuk/testablecodemobius/business/transfer/validation
答案 1 :(得分:3)
我认为你应该RxJava CombineLatest ,所以你需要所有的表单输入都产生一个observable,然后你只需要组合它并调整视图
作为参考,您可以查看:
https://medium.com/@etiennelawlor/rxjava-on-the-sign-in-screen-9ecb66b88572
Using RxJava for email login validation, an observable is emitting twice
======
示例:
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();
});
}
}