📜 ⬆️ ⬇️

Simple field validation

In the course of professional activity, one has to constantly face the validation of text input fields on the screens of mobile devices. Most often this is a couple of screens per application (SignIn, SignUp, Profile).

For the sake of this, external dependencies seem to be excessive. For example, the same Hibernate Validator adds about 8000 methods and 1 MB to the weight of the final apk, which looks ... redundant)

The search for some successful solution on the Internet was not successful, so it was decided to file one’s own. After consulting with a colleague (with iOS directions), we came up with the idea of ​​a concise solution, which was later implemented on each of the platforms.
')
Implementation of this idea for Android and I want to share. But I’ll warn you right away that, for the sake of simplicity, ideas will be used in an extremely simple version, perhaps even naive. Plus, in the current implementation of the idea, Rx is not used.

So. It all starts with a very simple interface:

public interface Validator<T> { boolean isValid(T value); String getDescription(); } 

Actually, that's all)

Next, we will need its implementation to build together atomic validators of the same type:

 public class ValidatorsComposer<T> implements Validator<T> { private final List<Validator<T>> validators; private String description; public ValidatorsComposer(Validator<T>... validators) { this.validators = Arrays.asList(validators); } @Override public boolean isValid(T value) { for (Validator<T> validator : validators) { if (!validator.isValid(value)) { description = validator.getDescription(); return false; } } return true; } @Override public String getDescription() { return description; } } 

An example of this is validation of an email field. To do this, create two atomic validators:

 public class EmptyValidator implements Validator<String> { @Override public boolean isValid(String value) { return !TextUtils.isEmpty(value); } @Override public String getDescription() { return "Field must not be empty"; } } 

 public class EmailValidator implements Validator<String> { @Override public boolean isValid(String value) { return Patterns.EMAIL_ADDRESS.matcher(value).matches(); } @Override public String getDescription() { return "Email should be in \'a@a.com\' format"; } } 

And, actually, a use case:

 final ValidatorsComposer<String> emailValidatorsComposer = new ValidatorsComposer<>(new EmptyValidator(), new EmailValidator()); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (emailValidatorsComposer.isValid(emailEditText.getText().toString())) { errorTextView.setText(null); } else { errorTextView.setText(emailValidatorsComposer.getDescription()); } } }); 

Also, this idea is also suitable for validating DataObjects and then displaying an error on the screen. For example, create a validator for a DataObject User:

 public class User { public final String name; public final Integer age; public final Gender gender; public enum Gender {MALE, FEMALE} public User(String name, Integer age, Gender gender) { this.name = name; this.age = age; this.gender = gender; } } 

 public class UserValidator implements Validator<User> { private String description; @Override public boolean isValid(User value) { if (value == null) { description = "User must not be null"; return false; } final String name = value.name; if (TextUtils.isEmpty(name)) { description = "User name must not be blank"; return false; } final Integer age = value.age; if (age == null) { description = "User age must not be blank"; return false; } else if (age < 0) { description = "User age must be above zero"; return false; } else if (age > 100) { description = "User age is to much"; return false; } final User.Gender gender = value.gender; if (gender == null) { description = "User gender must not be blank"; return false; } return true; } @Override public String getDescription() { return description; } } 

And use case:

 final Validator<User> userValidator = new UserValidator(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { User user = new User(null, 12, User.Gender.MALE); if (userValidator.isValid(user)) { errorTextView.setText(null); } else { errorTextView.setText(userValidator.getDescription()); } } }); 

Validation options can be very different: from validation to the event (by pressing a button, for example, as shown in the examples above), to dynamic validation (at the time of entering text):

 emailEditText.addTextChangedListener(new SimpleTextWatcher() { @Override public void afterTextChanged(Editable s) { if (!emailValidatorsComposer.isValid(s.toString())) { errorTextView.setText(emailValidatorsComposer.getDescription()); } } }); 

As well as the strategy of displaying errors can also be completely different: from the focus on the error field with the display of the error text and the display of the keyboard (preferred in my opinion) to the display of all errors on the screen at once (this is quite often found in android applications). Google recommendations for showing errors can be viewed at the link .

As a result, we get an extremely simple and at the same time flexible idea of ​​validation of fields and data objects, which in fact does not make the project heavier and is realized by clicking the fingers. How be profit)

Source: https://habr.com/ru/post/332642/


All Articles