TextWatcher är ett Android-gränssnitt som gör det möjligt att spåra textändringar i EditText och andra TextView i realtid. Utvecklaren får meddelanden i tre steg: före ändringen, under ändringen och efter ändringen av textinnehållet. Enligt Android Developers, 2026 används TextWatcher i de flesta applikationer för inmatningsvalidering, teckenräkning, implementering av sökning med autokomplettering och dynamisk textformatering. Gränssnittet är oumbärligt i formulär där omedelbar reaktion på varje tangenttryckning krävs.
Huvudpunkter
TextWatcher är ett gränssnitt från paketet android.text som meddelar applikationen om textändringar i Editable-objekt. Vid varje inmatning, borttagning eller ersättning av ett tecken anropar TextWatcher sekventiellt tre metoder och skickar information om ändringarnas position. Detta gör att utvecklaren kan reagera omedelbart på användarens handlingar — utan extra knappar eller triggers.
De viktigaste användningsscenarierna inkluderar realtidsvalidering av fält: kontroll av e-post vid varje teckeninmatning, räkning av återstående tecken i ett fält med längdbegränsning, implementering av sökning med fördröjd begäran via debounce. TextWatcher används också för inmatningsformatering — till exempel automatisk placering av mellanslag i ett telefonnummer eller tillägg av en mask för ett datum.
Enligt Android Developers finns TextWatcher i 70% av applikationer som arbetar med formulär. Bibliotek som Material Design Components och TextInputEditText använder TextWatcher internt för felhantering och visning av räknare. Att förstå hur detta gränssnitt fungerar är nödvändigt för varje Android-utvecklare.
TextWatcher ansluts till valfritt TextView- eller EditText-objekt via metoden addTextChangedListener. När användaren matar in eller tar bort ett tecken anropar Android först beforeTextChanged, sedan onTextChanged och slutligen afterTextChanged. I parametrarna för varje metod överförs data om det ändrade intervallet: startposition, antal borttagna tecken och antal tillagda tecken.
Det är viktigt att förstå att efter anropet av afterTextChanged innehåller Editable-objektet redan det aktuella värdet. Därför är det bekvämt att kontrollera fältets slutliga text i afterTextChanged. Fram till den tidpunkten är data ännu inte fullt uppdaterad. Utvecklare blandar ofta ihop metodernas syfte och använder onTextChanged för slutlig validering, även om det korrekta valet är afterTextChanged.
Vid varje infogning, ersättning eller borttagning av ett tecken utförs anropskedjan garanterat fullständigt. Men om texten ändras inuti afterTextChanged (via clear, append, insert), kommer TextWatcher att aktiveras rekursivt. Detta är den vanligaste orsaken till StackOverflowError i Android-formulär. För att förhindra rekursion används en blockeringsflagga.
Var och en av de tre metoderna spelar sin roll i textändringens livscykel. Metoden beforeTextChanged(CharSequence s, int start, int count, int after) anropas innan ändringar tillämpas. Den överför den aktuella strängens tillstånd, startpositionen för ändringen, antalet tecken som ska tas bort och antalet tecken som ska läggas till. Här kan det tidigare värdet sparas eller villkor kontrolleras före modifiering.
Metoden onTextChanged anropas under ändringen, när tecken redan har tagits bort men nya ännu inte har infogats. Parametrar: text efter borttagning, startposition, antal borttagna tecken och antal tecken som ska läggas till. Denna metod är användbar för animering eller loggning, men inte för arbete med den aktuella slutliga texten — den är ännu inte komplett.
Metoden afterTextChanged är den mest efterfrågade. Den tar emot ett Editable-objekt och anropas efter att ändringarna har tillämpats fullständigt. I denna metod kan man läsa fältets slutliga värde, utföra validering, uppdatera UI och ändra text (med försiktighet på grund av rekursion).
Praktiskt exempel — en teckenräknare för ett inmatningsfält som uppdateras vid varje textändring. Ett sådant element förekommer ofta i kontaktformulär, inlägg och meddelanden med längdbegränsning. Implementering via TextWatcher kräver bara några rader och inga tredjepartsbibliotek.
val editText = findViewById<EditText>(R.id.edit_text)
val counterText = findViewById<TextView>(R.id.counter)
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(
s: CharSequence?, start: Int,
count: Int, after: Int
) {}
override fun onTextChanged(
s: CharSequence?, start: Int,
before: Int, count: Int
) {}
override fun afterTextChanged(s: Editable?) {
val len = s?.length ?: 0
counterText.text = "$len / 200"
}
})
I exemplet tar afterTextChanged-metoden emot fältets aktuella innehåll via parametern s av typen Editable. Textlängden uppdateras i en separat TextView. För att undvika rekursion i detta fall ändras endast counterText, inte själva EditText, så ingen loop uppstår. Vid en gräns på 200 tecken kan inmatning blockeras efter överskridande.
Metoderna beforeTextChanged och onTextChanged förblir tomma, eftersom slutläget är tillräckligt för att räkna längden. Om loggning av varje ändring behövs kan koden läggas till i onTextChanged. Sådan flexibilitet gör TextWatcher till ett universellt verktyg för alla scenarier med textinmatning.
Realtidsvalidering förbättrar användarupplevelsen avsevärt: användaren ser felet omedelbart efter att ha matat in ett felaktigt värde, inte efter att ha tryckt på skicka-knappen. TextWatcher möjliggör omedelbar kontroll av e-post, lösenord, telefonnummer och andra fält. Resultatet visas via setError i EditText eller via en separat TextView med felmeddelande.
fun validateEmail(emailEditText: EditText) {
emailEditText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
val email = s?.toString () ?: ""
if (email.isNotBlank() &&
!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
emailEditText.error = "Invalid email address"
} else {
emailEditText.error = null
}
}
override fun beforeTextChanged(...) {}
override fun onTextChanged(...) {}
})
}
I exemplet används den inbyggda Patterns.EMAIL_ADDRESS från Android SDK för e-postkontroll. Om texten inte är tom och inte matchar mönstret tilldelas fältet ett fel via egenskapen error. Vid korrekt inmatning rensas felet. Det är viktigt att inte köra validering på ett tomt fält — användaren har kanske inte börjat mata in än, och felmeddelandet skulle vara för tidigt.
För lösenord och telefonnummer används anpassade reguljära uttryck eller specialiserade bibliotek. Till exempel, för att kontrollera lösenordskomplexitet kan man räkna antalet siffror, versaler och gemener. TextWatcher möjliggör uppdatering av lösenordsstyrkeindikatorn i realtid, vilket positivt påverkar registreringskonverteringen.
Det första och mest kritiska misstaget — rekursivt anrop. Om texten i samma EditText ändras inuti afterTextChanged (via s.clear(), s.append() eller s.insert()), kommer TextWatcher att aktiveras igen. Detta skapar en oändlig loop som slutar med StackOverflowError. Lösningen — använd en blockeringsflagga isUpdating eller kontrollera om texten faktiskt har ändrats.
Det andra vanliga problemet — minnesläcka. TextWatcher innehåller en implicit referens till Activity eller Fragment via en anonym klass. Om listen inte tas bort när View förstörs kan garbage collector inte frigöra minnet. Lösningen — använd livscykelkomponenter eller anropa explicit removeTextChangedListener i onDestroyView.
Det tredje misstaget — användning av fel metod. Vissa utvecklare utför slutlig validering i onTextChanged utan att vänta på afterTextChanged. I onTextChanged är texten ännu inte fullt uppdaterad och läsning av det slutliga värdet kan returnera felaktiga data. Rätt tillvägagångssätt — placera all logik för läsning och kontroll av slutlig text i afterTextChanged.
| Metod | Anropstillfälle | Syfte | |
|---|---|---|---|
| beforeTextChanged | Före ändring | Spara tidigare tillstånd | Ja |
| onTextChanged | Under ändring | Loggning, animering | Nej |
| afterTextChanged | Efter ändring | Validering, räkning, UI-uppdatering | Ja |
Det fjärde misstaget — flera tillägg av TextWatcher. Om addTextChangedListener har anropats flera gånger för samma EditText kommer alla listeners att bearbeta samma ändring. I formulär med dynamisk tillägg av Views leder detta till dubbelarbete av kontroller och oförutsägbart beteende. Kontrollera alltid om listen redan har lagts till tidigare eller använd en enda instans.
Vanliga frågor
OnTextChanged anropas vid tidpunkten för textändring, när nya tecken ännu inte har lagts till. Denna metod är lämplig för animering och loggning. AfterTextChanged anropas efter fullständig tillämpning av ändringarna och ger tillgång till den slutliga texten via parametern Editable. För validering och värdesavläsning, använd afterTextChanged.
Använd en blockeringsflagga av typen Boolean som sätts till true innan texten ändras inuti afterTextChanged. I början av metoden, kontrollera flaggan: om den är true — avsluta. Alternativt kan man jämföra det gamla och nya värdet och endast ändra texten vid en verklig skillnad.
Ja, absolut. Den anonyma klassen för TextWatcher håller en referens till Activity via en closure. Om listen inte tas bort kan Activity inte samlas in av garbage collector. Anropa alltid removeTextChangedListener i onDestroyView för Fragment eller onDestroy för Activity.
Ja, men med försiktighet. I RecyclerView återanvänds ViewHolders och TextWatcher från föregående position kan förbli aktiv. Ta alltid bort den gamla TextWatcher innan du installerar en ny i metoden onBindViewHolder. Använd taggar eller separata fält i ViewHolder för att lagra referensen till listen.
För sökfältet, använd afterTextChanged i kombination med debounce (fördröjning). Implementera en timer på 300-500 ms som återställs vid varje ny textändring. Detta förhindrar att en begäran skickas till servern vid varje tangenttryckning och minskar API-belastningen.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också