Visit Sponsor

Written by 8:23 am Android

Android TextWatcher Example – Listen for Text Input Changes

In Android apps, text input from users often needs to be tracked in real time — for form validation, live search, formatting, or dynamic UI updates. The TextWatcher interface provides a clean way to listen for text changes in text fields such as EditText.

This guide explains how to implement TextWatcher with practical examples and best practices for robust input handling.

What Is TextWatcher?

TextWatcher is an interface in Android that lets you listen to text changes in editable text views (e.g., EditText). It provides three callback methods:

  • beforeTextChanged() — Invoked before the text is changed
  • onTextChanged() — Invoked as the text is being changed
  • afterTextChanged() — Invoked after the text has changed

These callbacks allow fine-grained control over text change events.

When to Use TextWatcher

Use TextWatcher when you need to:

  • Validate input as the user types
  • Enable/disable UI elements based on text
  • Implement live search or filtering
  • Format text (like auto-uppercase, masking, etc.)

TextWatcher is not suitable for performance-heavy operations on each keystroke; use throttling or debounce for such cases.

Add an EditText in Layout

Here’s a simple EditText in your XML (activity_main.xml):

<EditText
    android:id="@+id/etInput"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Type something..."
    android:padding="12dp"/>

This will be the input field where text changes are tracked.

Implementing TextWatcher in Java

In your Activity or Fragment:

EditText etInput = findViewById(R.id.etInput);

etInput.addTextChangedListener(new TextWatcher() {

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // Called before text is changed
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // Called as text changes
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Called after the text has changed
    }
});

This attaches a TextWatcher to the EditText.

Example: Live Input Validation

etInput.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {
        String input = s.toString().trim();
        if (input.length() < 5) {
            etInput.setError("Minimum 5 characters required");
        }
    }

    // Before and onTextChanged can remain empty if unused
    @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
});

In this example, afterTextChanged() validates that the user has entered at least five characters.

Example: Live Search Filtering

For filtering a list based on text input:

etInput.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        adapter.getFilter().filter(s);
    }

    @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override public void afterTextChanged(Editable s) {}
});

This calls the adapter’s filter method as text changes, enabling live search behavior.

Formatting Text Automatically

TextWatcher can be used to automatically format input, like uppercasing text:

etInput.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {
        etInput.removeTextChangedListener(this);

        String upperText = s.toString().toUpperCase();
        etInput.setText(upperText);
        etInput.setSelection(upperText.length());

        etInput.addTextChangedListener(this);
    }

    @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
});

Note: When modifying text inside a TextWatcher, remove and re-add the watcher to prevent recursive triggers.

Best Practices

From real Android engineering experience:

  • Use afterTextChanged() for final text processing
  • Avoid heavy logic inside onTextChanged()
  • Use debounce/throttle for search filtering to reduce frequent operations
  • Remove TextWatcher when not needed (e.g., in View recycling)

These practices prevent performance pitfalls and maintain clean UI feedback.

Common Issues and Fixes

Issue: Cursor jumps to start after text modification
➡ When updating text programmatically, always restore cursor position.

Issue: UI lag during typing
➡ Avoid heavy operations on main thread; use debounced background calls.

Issue: Recursive change loop
➡ Temporarily remove the TextWatcher when setting text programmatically.

TextWatcher with ViewModel and LiveData (Modern Pattern)

If you’re using MVVM:

etInput.addTextChangedListener(new TextWatcher() {
    @Override
    public void afterTextChanged(Editable s) {
        viewModel.onTextChanged(s.toString());
    }
    @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
});

Your ViewModel can process text and expose results via LiveData for UI observation.

Summary

TextWatcher is a versatile interface that allows you to monitor and react to text input in real time. It’s essential for form validation, live search, input formatting, and more. When used with best practices and modern patterns, it enables responsive and intuitive user interactions.

Visited 12 times, 1 visit(s) today
Close