Last active
October 18, 2020 18:25
-
-
Save jayrambhia/52c65afbb74e204a14de1c32b3fcefac to your computer and use it in GitHub Desktop.
Post about form validation using RxJava http://www.jayrambhia.com/blog/rx-form-validations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface AvailabilityChecker { | |
Observable<ValidationResult<String>> isEmailAvailable(@NonNull String email); | |
Observable<ValidationResult<String>> isUsernameAvailable(@NonNull String email); | |
ValidationResult<String> isEmailAvailableSync(@NonNull String email); | |
ValidationResult<String> isUsernameAvailableSync(@NonNull String email); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_subscription = Observable.combineLatest(usernameSubject, emailSubject, phoneObservable, | |
new Func3<Boolean, Boolean, Boolean, Boolean>() { | |
@Override | |
public Boolean call(Boolean validUsername, Boolean validEmail, Boolean validPhone) { | |
return validUsername && validEmail && validPhone; | |
} | |
}).subscribe(new Action1<Boolean>() { | |
@Override | |
public void call(Boolean enabled) { | |
submitButton.setEnabled(enabled); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Subscription _subscription = Observable.combineLatest(usernameObservable, emailObservable, phoneObservable, | |
new Func3<Boolean, Boolean, Boolean, Boolean>() { | |
@Override | |
public Boolean call(Boolean validUsername, Boolean validEmail, Boolean validPhone) { | |
return validUsername && validEmail && validPhone; | |
} | |
}).subscribe(new Action1<Boolean>() { | |
@Override | |
public void call(Boolean enabled) { | |
submitButton.setEnabled(enabled); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RandomAvailabilityChecker implements AvailabilityChecker { | |
private static final String TAG = "RandAvailabilityChecker"; | |
private Random random; | |
public RandomAvailabilityChecker() { | |
random = new Random(); | |
} | |
@Override | |
public Observable<ValidationResult<String>> isEmailAvailable(@NonNull final String email) { | |
return Observable.defer(new Func0<Observable<ValidationResult<String>>>() { | |
@Override | |
public Observable<ValidationResult<String>> call() { | |
return Observable.just(isEmailAvailableSync(email)); | |
} | |
}).delay(1200, TimeUnit.MILLISECONDS); | |
} | |
@Override | |
public Observable<ValidationResult<String>> isUsernameAvailable(@NonNull final String username) { | |
return Observable.defer(new Func0<Observable<ValidationResult<String>>>() { | |
@Override | |
public Observable<ValidationResult<String>> call() { | |
return Observable.just(isUsernameAvailableSync(username)); | |
} | |
}).delay(3000, TimeUnit.MILLISECONDS); | |
} | |
@Override | |
public ValidationResult<String> isEmailAvailableSync(@NonNull String email) { | |
int rand = random.nextInt(12); | |
if (rand > 4) { | |
return ValidationResult.success(email); | |
} | |
return ValidationResult.failure("Email is already taken", email); | |
} | |
@Override | |
public ValidationResult<String> isUsernameAvailableSync(@NonNull String username) { | |
int rand = random.nextInt(12); | |
if (rand > 4) { | |
return ValidationResult.success(username); | |
} | |
return ValidationResult.failure("Username is already taken", username); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static Observable<String> getTextWatcherObservable(@NonNull final EditText editText) { | |
final PublishSubject<String> subject = PublishSubject.create(); | |
editText.addTextChangedListener(new TextWatcher() { | |
@Override | |
public void beforeTextChanged(CharSequence s, int start, int count, int after) {} | |
@Override | |
public void onTextChanged(CharSequence s, int start, int before, int count) {} | |
@Override | |
public void afterTextChanged(Editable s) { | |
subject.onNext(s.toString()); | |
} | |
}); | |
return subject; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Observable<String> emailObservable = RxHelper.getTextWatcherObservable(emailView); | |
Observable<String> usernameObservable = RxHelper.getTextWatcherObservable(usernameView); | |
Observable<String> phoneObservable = RxHelper.getTextWatcherObservable(phoneView); | |
Subscription _subscription = Observable.combineLatest(emailObservable, usernameObservable, | |
phoneObservable, new Func3<String, String, String, Boolean>() { | |
@Override | |
public Boolean call(String email, String username, String phone) { | |
return false; | |
} | |
}).subscribe(new Action1<Boolean>() { | |
@Override | |
public void call(Boolean enabled) { | |
Log.i(TAG, "submit button enabled: " + enabled); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ValidationResult<T> { | |
private boolean valid; | |
private String reason; | |
private T data; | |
public static <T> ValidationResult<T> success(T t) { | |
return new ValidationResult<>(true, null, t); | |
} | |
public static <T> ValidationResult<T> failure(@Nullable String reason, T t) { | |
return new ValidationResult<>(false, reason, t); | |
} | |
private ValidationResult(boolean valid, @Nullable String reason, T t) { | |
this.valid = valid; | |
this.reason = reason; | |
this.data = t; | |
} | |
public boolean isValid() { | |
return valid; | |
} | |
@Nullable | |
public String getReason() { | |
return reason; | |
} | |
public T getData() { | |
return data; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Observable<Boolean> emailObservable = RxHelper.getTextWatcherObservable(emailView) | |
.debounce(800, TimeUnit.MILLISECONDS) | |
.subscribeOn(Schedulers.io()) | |
.map(new Func1<String, ValidationResult<String>>() { | |
@Override | |
public ValidationResult<String> call(String s) { | |
return validateEmail(s); | |
} | |
}).map(new Func1<ValidationResult<String>, ValidationResult<String>>() { | |
@Override | |
public ValidationResult<String> call(ValidationResult<String> result) { | |
if (!result.isValid()) { | |
return result; | |
} | |
return availabilityChecker.isEmailAvailableSync(result.getData()); | |
} | |
}).observeOn(AndroidSchedulers.mainThread()) | |
.map(new Func1<ValidationResult<String>, Boolean>() { | |
@Override | |
public Boolean call(ValidationResult<String> result) { | |
emailView.setError(result.getReason()); | |
return result.isValid(); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Observable<Boolean> emailObservable = RxHelper.getTextWatcherObservable(emailView) | |
.debounce(800, TimeUnit.MILLISECONDS) | |
.observeOn(AndroidSchedulers.mainThread()) | |
.map(new Func1<String, Boolean>() { | |
@Override | |
public Boolean call(String s) { | |
Log.i(TAG, "validate email: " + s); | |
ValidationResult result = validateEmail(s); | |
emailView.setError(result.getReason()); | |
return result.isValid(); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void setupObservables() { | |
emailSubject = PublishSubject.create(); | |
RxHelper.getTextWatcherObservable(emailView) | |
.debounce(800, TimeUnit.MILLISECONDS) | |
.map(new Func1<String, ValidationResult<String>>() { | |
@Override | |
public ValidationResult<String> call(String s) { | |
cancelEmailApiCall(); | |
return validateEmail(s); | |
} | |
}) | |
.subscribeOn(Schedulers.io()) | |
.observeOn(AndroidSchedulers.mainThread()) | |
.subscribe(new Action1<ValidationResult<String>>() { | |
@Override | |
public void call(ValidationResult<String> result) { | |
if (!result.isValid()) { | |
emailView.setError(result.getReason()); | |
emailSubject.onNext(false); | |
return; | |
} | |
callApiToValidateEmail(result.getData()); | |
} | |
}); | |
} | |
private void callApiToValidateEmail(@NonNull String email) { | |
cancelEmailApiCall(); | |
emailApiSubscription = availabilityChecker.isEmailAvailable(email) | |
.subscribeOn(Schedulers.io()) | |
.observeOn(AndroidSchedulers.mainThread()) | |
.subscribe(new Action1<ValidationResult<String>>() { | |
@Override | |
public void call(ValidationResult<String> result) { | |
emailView.setError(result.getReason()); | |
emailSubject.onNext(result.isValid()); | |
} | |
}); | |
} | |
private void cancelEmailApiCall() { | |
if (emailApiSubscription != null && !emailApiSubscription.isUnsubscribed()) { | |
emailApiSubscription.unsubscribe(); | |
emailApiSubscription = null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RxHelper.getTextWatcherObservable(emailView) | |
.map(new Func1<String, String>() { | |
@Override | |
public String call(String s) { | |
cancelEmailApiCall(); | |
return s; | |
} | |
}) | |
.debounce(800, TimeUnit.MILLISECONDS) | |
.... | |
Other stuff |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment