EditText Input Validations with Android

Input validation is a crucial part of creating effective and reliable Android applications. Without proper validation, user input can cause errors, crashes, and even security vulnerabilities. Fortunately, EditText in Android provides a number of built-in validation mechanisms to help developers ensure that user input is correct and meets specific requirements.

If you want to know more about EditText, please have a look at our main page (Android EditText).

Required Field validation

In the following example, we have an EditText with an id etName in the XML layout file. In the Kotlin code, we initialize the etName EditText using findViewById and set an OnEditorActionListener to trigger the validation when the Done action is performed. In the validateName() function, we retrieve the entered text, trim any leading or trailing spaces, and check if it is empty using TextUtils.isEmpty(). If the name is empty, we set an error message on the EditText using setError() to indicate that the field is required.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    etName = findViewById(R.id.etName)
    
    // Perform validation when a specific action is triggered
    etName.setOnEditorActionListener { _, actionId, _ ->
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            validateName()
            return@setOnEditorActionListener false
        }
        false
    }
}

private fun validateName() {
    val name = etName.text.toString().trim()
    if (TextUtils.isEmpty(name)) {
        etName.error = "Name is required"
    } else {
        // Name is not empty, perform further actions
    }
}

Length validation

To demonstrate length validation, we have an EditText with an id etPassword in the XML layout file. In the Kotlin code, we set a maximum length of 8 characters for the password input using an InputFilter. We also add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we check if the length of the password is less than the specified maximum length. If it is, we set an error message using setError() on the EditText to indicate the required length.

class MainActivity : AppCompatActivity() {
    private lateinit var etPassword: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etPassword = findViewById(R.id.etPassword)
        
        // Set maximum length for the password input
        val maxLength = 8
        val inputFilterArray = arrayOfNulls<InputFilter>(1)
        inputFilterArray[0] = InputFilter.LengthFilter(maxLength)
        etPassword.filters = inputFilterArray
        
        // Perform validation using a TextWatcher
        etPassword.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val password = s.toString().trim()
                if (password.length < maxLength) {
                    etPassword.error = "Password must be at least $maxLength characters"
                } else {
                    etPassword.error = null
                }
            }
        })
    }
}
EditText with required field validation
EditText with required field validation
EditText with minimum text length validation
EditText with minimum text length validation

Patterns matcher

In Android development, pattern matchers refer to classes or functions that allow you to search for specific patterns or structures within text or input data. They are used to identify and extract relevant information based on predefined patterns or rules.

Pattern matchers in Android often leverage regular expressions (regex) to define the patterns they are looking for. Regular expressions provide a flexible and powerful way to express complex search patterns.

One common use case for pattern matchers in Android is input validation. For example, if you have a form where users are required to enter an email address, you can use a pattern matcher to ensure that the input follows a valid email format. The pattern matcher will compare the entered text against a predefined regex pattern for email addresses and determine whether it matches or not.

Another example is parsing data from text or HTML. Suppose you have a string containing a list of URLs, and you want to extract the domain names from each URL. You can use a pattern matcher with a regex pattern to identify and extract the domain names from the string.

Pattern matchers in Android can be implemented using various APIs and classes provided by the Android framework, such as the Pattern class in the java.util.regex package. These classes offer methods for compiling regex patterns, performing matching operations, and extracting matched substrings.

By utilizing pattern matchers in Android, developers can effectively search for, validate, and extract data based on specific patterns or structures, enhancing the functionality and usability of their applications.

Some example patterns are the DOMAIN_NAME, EMAIL_ADDRESS, PHONE or WEB_URLmatches. We will show examples for the E-Mail and URL pattern matchers.

Email validation

To demonstrate an Email validation, we have put an EditText with an id etEmail in the XML layout file. The inputType attribute is set to “textEmailAddress” to enable the email address input type and provide email-specific keyboard features.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid email address using the isValidEmail() function. The isValidEmail() function uses the Patterns.EMAIL_ADDRESS constant and its associated regular expression to validate the email format.

If the entered value is not a valid email address or is empty, we set an error message using setError() on the EditText. Otherwise, if the input is a valid email address, we clear the error.

<EditText
    android:id="@+id/etEmail"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter your email"
    android:inputType="textEmailAddress"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Patterns
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etEmail: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etEmail = findViewById(R.id.etEmail)
        
        // Perform validation using a TextWatcher
        etEmail.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val email = s.toString().trim()
                if (TextUtils.isEmpty(email) || !isValidEmail(email)) {
                    etEmail.error = "Please enter a valid email address"
                } else {
                    etEmail.error = null
                }
            }
        })
    }
    
    private fun isValidEmail(email: String): Boolean {
        return Patterns.EMAIL_ADDRESS.matcher(email).matches()
    }
}

URL validation

To test a URL for valid format we can use once again a certain patterns matcher.

In this example, we have an EditText with an id etUrl in the XML layout file. The inputType attribute is set to “textUri” to allow the user to enter a URI or URL.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid URL using the isValidUrl() function. The isValidUrl() function uses the Patterns.WEB_URL constant and its associated regular expression to validate the URL format.

If the entered value is not a valid URL or is empty, we set an error message using setError() on the EditText. Otherwise, if the input is a valid URL, we clear the error.

<EditText
    android:id="@+id/etUrl"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter a URL"
    android:inputType="textUri"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Patterns
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etUrl: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etUrl = findViewById(R.id.etUrl)
        
        // Perform validation using a TextWatcher
        etUrl.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val url = s.toString().trim()
                if (TextUtils.isEmpty(url) || !isValidUrl(url)) {
                    etUrl.error = "Please enter a valid URL"
                } else {
                    etUrl.error = null
                }
            }
        })
    }
    
    private fun isValidUrl(url: String): Boolean {
        return Patterns.WEB_URL.matcher(url).matches()
    }
}
EditText Email Address Pattern Matcher Validation
EditText Email Address Pattern Matcher Validation
EditText URL Pattern Matcher Validation
EditText Email Address Pattern Matcher Validation

Date validation

For date validations we will put the inputType attribute to “date” to enable a date picker dialog for selecting a date.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid date using the isValidDate() function. The isValidDate() function attempts to parse the date string using a SimpleDateFormat with the format “yyyy-MM-dd”. If the parsing is successful and the date is valid, it returns true; otherwise, it returns false.

If the entered value is not a valid date or is empty, we set an error message using setError() on the EditText. Otherwise, if the input is a valid date, we clear the error.

<EditText
    android:id="@+id/etDate"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter a date (YYYY-MM-DD)"
    android:inputType="date"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*

class MainActivity : AppCompatActivity() {
    private lateinit var etDate: EditText
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etDate = findViewById(R.id.etDate)
        
        // Perform validation using a TextWatcher
        etDate.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val date = s.toString().trim()
                if (TextUtils.isEmpty(date) || !isValidDate(date)) {
                    etDate.error = "Please enter a valid date (YYYY-MM-DD)"
                } else {
                    etDate.error = null
                }
            }
        })
    }
    
    private fun isValidDate(date: String): Boolean {
        return try {
            dateFormat.isLenient = false
            dateFormat.parse(date)
            true
        } catch (e: ParseException) {
            false
        }
    }
}

Custom regex validation

Regex, short for Regular Expression, is a powerful and versatile tool used for pattern matching and manipulating text. It is a sequence of characters that defines a search pattern, allowing you to find, match, and manipulate strings based on specific criteria.

Think of regex as a language for describing patterns within text. Just like you might use keywords or phrases to search for information in a document, regex uses a combination of characters, symbols, and special syntax to define patterns. These patterns can be as simple as finding a specific word or as complex as extracting data from structured text.

For example, let’s say you have a long list of email addresses, and you want to extract all the addresses that belong to a specific domain, such as “@example.com”. Using regex, you can construct a pattern that matches this specific format and retrieve the desired email addresses, ignoring the rest.

Another example could be validating a phone number format. If you want to check if a phone number is in the format “XXX-XXX-XXXX” (where X represents a digit), you can use regex to define this pattern and verify if a given phone number matches it.

Regex is widely used in various domains, including text processing, data extraction, data validation, and programming. It provides a concise and flexible way to search, replace, and manipulate textual data based on specific patterns, making it an invaluable tool for tasks involving text analysis and manipulation.

Numeric input validation

class MainActivity : AppCompatActivity() {
    private lateinit var etNumber: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etNumber = findViewById(R.id.etNumber)
        
        // Perform validation using a TextWatcher
        etNumber.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val number = s.toString().trim()
                if (number.isNotEmpty() && !isNumeric(number)) {
                    etNumber.error = "Please enter a valid number"
                } else {
                    etNumber.error = null
                }
            }
        })
    }
    
    private fun isNumeric(str: String): Boolean {
        return str.matches("-?\\d+(\\.\\d+)?".toRegex())
    }
}

Password validation

In this example, we have an EditText with an id etPassword in the XML layout file. The inputType attribute is set to “textPassword” to hide the password characters as they are entered.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid password using the isValidPassword() function. The isValidPassword() function uses a regular expression (passwordRegex) to define the password validation rules.

In the provided example, the password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one digit. You can modify the regular expression in the isValidPassword() function to match your specific password validation rules.

If the entered value is not a valid password or is empty, we set an error message using setError() on the EditText. Otherwise, if the input is a valid password, we clear the error.

<EditText
    android:id="@+id/etPassword"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter your password"
    android:inputType="textPassword"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etPassword: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etPassword = findViewById(R.id.etPassword)
        
        // Perform validation using a TextWatcher
        etPassword.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val password = s.toString().trim()
                if (TextUtils.isEmpty(password) || !isValidPassword(password)) {
                    etPassword.error = "Please enter a valid password"
                } else {
                    etPassword.error = null
                }
            }
        })
    }
    
    private fun isValidPassword(password: String): Boolean {
        // Add your password validation rules here
        // Example: At least 8 characters with at least one uppercase letter, one lowercase letter, and one digit
        val passwordRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}\$"
        return password.matches(passwordRegex.toRegex())
    }
}

Range validation

In this example, we have an EditText with an id etNumber in the XML layout file. The inputType attribute is set to “number” to allow the user to enter numeric values.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid number within the specified range using the isValidNumber() function.

The isValidNumber() function attempts to convert the entered text to an integer value. If the conversion is successful, it checks if the number falls within the specified range (between minValue and maxValue). If the number is within the range, it returns true; otherwise, it returns false. If the conversion fails (due to non-numeric input), it also returns false.

If the entered value is not a valid number or is empty, we set an error message using setError() on the EditText to indicate that a number within the specified range is required. If the input is a valid number within the range, we clear the error.

<EditText
    android:id="@+id/etNumber"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter a number (between 1 and 100)"
    android:inputType="number"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etNumber: EditText
    private val minValue = 1
    private val maxValue = 100
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etNumber = findViewById(R.id.etNumber)
        
        // Perform validation using a TextWatcher
        etNumber.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val number = s.toString().trim()
                if (TextUtils.isEmpty(number) || !isValidNumber(number)) {
                    etNumber.error = "Please enter a number between $minValue and $maxValue"
                } else {
                    etNumber.error = null
                }
            }
        })
    }
    
    private fun isValidNumber(number: String): Boolean {
        return try {
            val value = number.toInt()
            value in minValue..maxValue
        } catch (e: NumberFormatException) {
            false
        }
    }
}

Phone number validation

In this example, we have an EditText with an id etPhoneNumber in the XML layout file. The inputType attribute is set to “phone” to allow the user to enter a phone number. This input type helps in displaying a numeric keyboard with additional symbols commonly used in phone numbers.

In the Kotlin code, we add a TextWatcher to the EditText to perform the validation. In the afterTextChanged() method, we retrieve the entered text, trim any leading or trailing spaces, and check if it is a valid phone number using the isValidPhoneNumber() function.

The isValidPhoneNumber() function uses PhoneNumberUtils.isGlobalPhoneNumber() to validate the phone number. It checks if the provided string is a valid global phone number according to the rules of the country or region the user is currently in.

If the entered value is not a valid phone number or is empty, we set an error message using setError() on the EditText to indicate that a valid phone number is required. If the input is a valid phone number, we clear the error.

<EditText
    android:id="@+id/etPhoneNumber"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter a phone number"
    android:inputType="phone"
    android:imeOptions="actionDone"
    />
import android.os.Bundle
import android.telephony.PhoneNumberUtils
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etPhoneNumber: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etPhoneNumber = findViewById(R.id.etPhoneNumber)
        
        // Perform validation using a TextWatcher
        etPhoneNumber.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val phoneNumber = s.toString().trim()
                if (TextUtils.isEmpty(phoneNumber) || !isValidPhoneNumber(phoneNumber)) {
                    etPhoneNumber.error = "Please enter a valid phone number"
                } else {
                    etPhoneNumber.error = null
                }
            }
        })
    }
    
    private fun isValidPhoneNumber(phoneNumber: String): Boolean {
        return PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)
    }
}

Note that you could also use a patterns matcher to validate the phone number. The code would look then something like the following.

import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Patterns
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var etPhoneNumber: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        etPhoneNumber = findViewById(R.id.etPhoneNumber)
        
        // Perform validation using a TextWatcher
        etPhoneNumber.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // Not needed for this example
            }
    
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Not needed for this example
            }
    
            override fun afterTextChanged(s: Editable?) {
                val phoneNumber = s.toString().trim()
                if (TextUtils.isEmpty(phoneNumber) || !isValidPhoneNumber(phoneNumber)) {
                    etPhoneNumber.error = "Please enter a valid phone number"
                } else {
                    etPhoneNumber.error = null
                }
            }
        })
    }
    
    private fun isValidPhoneNumber(phoneNumber: String): Boolean {
        return Patterns.PHONE.matcher(phoneNumber).matches()
    }
}

EasyValidation Library

The EasyValidation Library is a powerful and intuitive validation framework for Kotlin developers. It simplifies the process of validating user input by providing a fluent and declarative API. With EasyValidation, you can easily define validation rules and apply them to various data types, such as strings, numbers, and dates. It supports a wide range of validation rules, including required fields, minimum and maximum length, numeric ranges, regular expressions, and more. Here’s an example code snippet in Kotlin that demonstrates how to use the EasyValidation Library:

// Import the EasyValidation library
import com.easyvalidation.EasyValidation

// Create a validation instance
val validation = EasyValidation()

// Define validation rules for a string input
validation.addRule("username", "Please enter a valid username")
    .required()
    .minLength(6)
    .maxLength(20)

// Validate the input
val input = "john_doe"
val validationResult = validation.validate(input)

// Check if the input is valid
if (validationResult.isValid()) {
    println("Input is valid")
} else {
    val errorMessages = validationResult.getErrorMessages()
    println("Input is invalid. Errors: $errorMessages")
}

In this example, we create a validation instance using EasyValidation(). We then define validation rules for a string input called “username”. The rules specify that the username is required, must have a minimum length of 6 characters, and a maximum length of 20 characters. We validate the input using validation.validate(input), which returns a ValidationResult object. We can check if the input is valid using validationResult.isValid(). If it’s not valid, we can retrieve the error messages using validationResult.getErrorMessages().