Table of Contents
Understanding User Input in Android
Handling user input is at the core of any interactive app. In Android, user input usually comes from views such as EditText, Button, CheckBox, Switch, or more complex components. In this chapter, you will focus on how to read, validate, and react to input from the user in a typical Android app.
This chapter builds on the basic knowledge of Button, TextView, and EditText that you will see in the related chapters, and focuses on what happens after the user has provided some data.
Reading Text from Input Fields
The most common type of user input is plain text entered into an EditText. To use the typed value in your logic, you read the text from the view inside your activity or fragment.
You get the text as a CharSequence and then usually convert it to a String.
val nameEditText: EditText = findViewById(R.id.nameEditText)
val nameText: String = nameEditText.text.toString()For numeric input fields, you still read the content as text first, then convert it to a number. Since conversion can fail, you must handle invalid cases.
val ageEditText: EditText = findViewById(R.id.ageEditText)
val ageText = ageEditText.text.toString()
val age: Int? = ageText.toIntOrNull()
At this point age is nullable. If the user enters something that is not a valid integer, toIntOrNull() returns null. This is safer than using toInt(), which throws an exception on invalid input.
Always convert text input safely. Prefer toIntOrNull() or similar safe conversions. Never trust that user input has the correct format.
Basic Input Validation
Once you read the input, you usually need to check if it is valid before using it. Validation can include checks such as:
Length requirements, for example name should not be empty.
Format requirements, for example email must contain @.
Range checks, for example age must be between 0 and 120.
A typical pattern is to read the value, validate it, and show feedback if something is wrong.
val emailEditText: EditText = findViewById(R.id.emailEditText)
val email = emailEditText.text.toString()
if (email.isBlank()) {
emailEditText.error = "Email is required"
} else if (!email.contains("@")) {
emailEditText.error = "Enter a valid email"
} else {
// Email is "valid" according to these simple rules
}
Setting error on an EditText displays a small error message near the field. This is a simple way to guide the user without creating extra views.
For numeric input, combine safe conversion with range checks.
val ageEditText: EditText = findViewById(R.id.ageEditText)
val ageText = ageEditText.text.toString()
val age = ageText.toIntOrNull()
if (age == null) {
ageEditText.error = "Enter a valid number"
} else if (age <= 0) {
ageEditText.error = "Age must be positive"
} else {
// Age is valid
}
Never perform calculations or network requests with unvalidated input. Always check for null, correct format, and reasonable ranges before using user data.
Combining Input with Buttons
Often you wait for the user to press a button before reading and checking the input. This ensures that validation happens at a clear moment, such as when the user taps a "Submit" or "Save" button.
Inside a button click listener, you usually perform three steps. Read input from one or more views. Validate the values. If valid, continue with the next action, such as updating the UI, saving data, or starting another activity.
val nameEditText: EditText = findViewById(R.id.nameEditText)
val submitButton: Button = findViewById(R.id.submitButton)
submitButton.setOnClickListener {
val name = nameEditText.text.toString()
if (name.isBlank()) {
nameEditText.error = "Name cannot be empty"
return@setOnClickListener
}
// Use the valid input, for example:
Toast.makeText(this, "Hello, $name!", Toast.LENGTH_SHORT).show()
}
Using return@setOnClickListener lets you exit early if validation fails, so the rest of the code runs only when the input is valid.
Reacting to Changes While the User Types
Sometimes you want to react while the user is still typing, not only when they press a button. For example, you may want to enable or disable a button depending on whether the field is filled, or display live validation feedback.
EditText allows you to register a listener that is notified whenever its text changes. In Kotlin you can use addTextChangedListener to listen to text changes with a concise syntax.
val usernameEditText: EditText = findViewById(R.id.usernameEditText)
val continueButton: Button = findViewById(R.id.continueButton)
usernameEditText.addTextChangedListener { editable ->
val text = editable?.toString().orEmpty()
continueButton.isEnabled = text.isNotBlank()
}Here the button becomes enabled only when the user has typed some text. This creates a more guided and responsive user experience.
You can also clear previous errors as soon as the user starts correcting their input.
usernameEditText.addTextChangedListener {
usernameEditText.error = null
}Limiting and Formatting Input
User input can be restricted or shaped at the view level before the user even finishes typing. This reduces the chance of invalid values and reduces how much validation logic you need.
In the XML layout, you can limit the maximum length of text and control what kind of keyboard appears.
<EditText
android:id="@+id/phoneEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone"
android:maxLength="15" />
android:inputType influences both the keyboard and basic input rules. For example, number shows a numeric keyboard and restricts input to digits, and textPassword hides the characters.
You can also perform additional formatting as the user types, for example adding spaces or dashes, but that typically involves more advanced components or custom code which will be discussed in more specialized topics.
Use android:inputType and android:maxLength to prevent invalid data before it is entered. Prevention is usually better than fixing invalid input later.
Handling Multiple Inputs Together
Most real forms contain several fields that together represent a single logical action, such as signing in, registering, or creating a note. Handling multiple inputs means coordinating their values and validations before performing the final action.
A common approach is to gather all values inside a single method that is triggered by a button tap, then validate everything at once.
private fun submitForm() {
val email = emailEditText.text.toString()
val password = passwordEditText.text.toString()
var isValid = true
if (email.isBlank()) {
emailEditText.error = "Email required"
isValid = false
}
if (password.length < 6) {
passwordEditText.error = "Password too short"
isValid = false
}
if (!isValid) {
return
}
// All inputs passed validation
performLogin(email, password)
}
You can call submitForm() from a button click listener to keep the code organized.
Hiding the Keyboard
After the user finishes typing, especially when they press a button, you might want to hide the on screen keyboard. While there are several ways to do this, a common approach from an activity is to use the input method manager.
fun hideKeyboard(view: View) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
You can call this from your click listener and pass the current view, often the button or the EditText. This improves usability by clearing the screen once the important action is complete.
Preventing Crashes from Invalid Input
User input is unpredictable. To keep your app stable, you must always assume that the user can enter unexpected values. This includes empty strings, extremely long values, wrong formats, and even pasted content.
Key practices to prevent crashes include safe conversions such as toIntOrNull(), null checks for user provided data, and careful use of indices or substring operations.
If you parse numbers, always handle the null case. If you read text and then access characters by index, always check the length first.
Never assume that input is safe. Validate and sanitize all user input before using it. Unsafe assumptions about user data are a common cause of crashes and security problems.
Showing Feedback Based on Input
Good user input handling is not only about reading and validating data. It is also about giving clear feedback. This can include:
Showing an error directly on the input field with editText.error.
Using a Toast or Snackbar to show a brief message.
Updating a TextView to reflect accepted input.
Enabling or disabling buttons based on whether the input is valid.
Here is a simple example that shows a Snackbar when the user submits valid input.
submitButton.setOnClickListener { view ->
val message = messageEditText.text.toString()
if (message.isBlank()) {
messageEditText.error = "Message cannot be empty"
} else {
Snackbar.make(view, "Message sent", Snackbar.LENGTH_SHORT).show()
messageEditText.text.clear()
}
}In this pattern, the user sees exactly what went wrong, and also receives confirmation when everything works correctly.
Summary
Handling user input in Android involves reading values from views, validating and converting them safely, reacting to changes while the user types, and providing clear feedback. By combining input fields with validation logic and appropriate feedback, you can build forms and interactions that feel reliable, responsive, and friendly to the user.