Best Practice: Input Validation (Android)
This java class implements a TextWatcher
to "watch" your edit text, watching any changes done to the text:
public abstract class TextValidator implements TextWatcher { private final TextView textView; public TextValidator(TextView textView) { this.textView = textView; } public abstract void validate(TextView textView, String text); @Override final public void afterTextChanged(Editable s) { String text = textView.getText().toString(); validate(textView, text); } @Override final public void beforeTextChanged(CharSequence s, int start, int count, int after) { /* Needs to be implemented, but we are not using it. */ } @Override final public void onTextChanged(CharSequence s, int start, int before, int count) { /* Needs to be implemented, but we are not using it. */ }}
And in your EditText
, you can set that text watcher to its listener
editText.addTextChangedListener(new TextValidator(editText) { @Override public void validate(TextView textView, String text) { /* Insert your validation rules here */ }});
One approach (which I am using) is you should have a helper for validating inputs such as:
- Nullity (or emptiness)
- Dates
- Passwords
- Emails
- Numerical values
- and others
here's an exerpt from my ValidationHelper class:
public class InputValidatorHelper { public boolean isValidEmail(String string){ final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; Pattern pattern = Pattern.compile(EMAIL_PATTERN); Matcher matcher = pattern.matcher(string); return matcher.matches(); } public boolean isValidPassword(String string, boolean allowSpecialChars){ String PATTERN; if(allowSpecialChars){ //PATTERN = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})"; PATTERN = "^[a-zA-Z@#$%]\\w{5,19}$"; }else{ //PATTERN = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,20})"; PATTERN = "^[a-zA-Z]\\w{5,19}$"; } Pattern pattern = Pattern.compile(PATTERN); Matcher matcher = pattern.matcher(string); return matcher.matches(); } public boolean isNullOrEmpty(String string){ return TextUtils.isEmpty(string); } public boolean isNumeric(String string){ return TextUtils.isDigitsOnly(string); } //Add more validators here if necessary}
Now the way I use this class is this:
InputValidatorHelper inputValidatorHelper = new InputValidatorHelper();StringBuilder errMsg = new StringBuilder("Unable to save. Please fix the following errors and try again.\n");//Validate and Saveboolean allowSave = true;if (user.getEmail() == null && !inputValidatorHelper.isValidEmail(user_email)) { errMsg.append("- Invalid email address.\n"); allowSave = false;}if (inputValidatorHelper.isNullOrEmpty(user_first_name)) { errMsg.append("- First name should not be empty.\n"); allowSave = false;}if(allowSave){ //Proceed with your save logic here}
You can call your validation by using TextWatcher
which is attached via EditText#addTextChangedListener
example:
txtName.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { //Do nothing } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { validate(); }});