TextWatcher, EditText ve diğer TextView'lerdeki metin değişikliklerini gerçek zamanlı olarak izlemeyi sağlayan bir Android arayüzüdür. Geliştirici, üç aşamada bildirim alır: değişiklikten önce, değişiklik sırasında ve metin içeriğinin değişmesinden sonra. Android Developers, 2026'ya göre, TextWatcher çoğu uygulamada giriş doğrulama, karakter sayma, otomatik tamamlamalı arama uygulama ve dinamik metin biçimlendirme için kullanılır. Arayüz, her tuş vuruşunda anında yanıt gereken formlarda vazgeçilmezdir.
Önemli Noktalar
TextWatcher, android.text paketinden, Editable nesnelerindeki metin değişiklikleri hakkında uygulamayı bilgilendiren bir arayüzdür. Her karakter girişi, silme veya değiştirmede, TextWatcher sırayla üç yöntemi çağırır ve değişikliklerin konumu hakkında bilgi iletir. Bu, geliştiricinin ek düğmeler veya tetikleyiciler olmadan kullanıcı eylemlerine anında tepki vermesini sağlar.
Ana kullanım durumları gerçek zamanlı alan doğrulama içerir: her karakter yazarken e-posta kontrolü, uzunluk sınırı olan bir alanda kalan karakterleri sayma, debounce ile gecikmeli istek arama uygulama. TextWatcher ayrıca giriş biçimlendirme için de kullanılır — örneğin, bir telefon numarasına otomatik olarak boşluk ekleme veya bir tarih için maske ekleme.
Android Developers'a göre, TextWatcher formlarla çalışan uygulamaların %70'inde bulunur. Material Design Components ve TextInputEditText gibi kütüphaneler, hata durumlarını yönetmek ve sayaçları görüntülemek için dahili olarak TextWatcher kullanır. Bu arayüzün nasıl çalıştığını anlamak her Android geliştiricisi için gereklidir.
TextWatcher, addTextChangedListener yöntemi aracılığıyla herhangi bir TextView veya EditText nesnesine bağlanır. Kullanıcı bir karakter yazdığında veya sildiğinde, Android önce beforeTextChanged'i, sonra onTextChanged'i ve son olarak afterTextChanged'i çağırır. Her yöntemin parametreleri, değiştirilen aralık hakkında veri içerir: başlangıç konumu, silinen karakter sayısı ve eklenen karakter sayısı.
afterTextChanged'i çağırdıktan sonra Editable nesnesinin zaten geçerli değeri içerdiğini anlamak önemlidir. Bu nedenle, alanın son metnini afterTextChanged'de kontrol etmek uygundur. Bu noktadan önce, veriler henüz tam olarak güncellenmemiştir. Geliştiriciler genellikle yöntemlerin amacını karıştırır ve son doğrulama için onTextChanged'i kullanır, ancak doğru seçim afterTextChanged'dir.
Her karakter ekleme, değiştirme veya silme işleminde, çağrı zincirinin tamamen yürütülmesi garanti edilir. Ancak, afterTextChanged içinde metin değiştirilirse (clear, append, insert aracılığıyla), TextWatcher özyinelemeli olarak tetiklenir. Bu, Android formlarında StackOverflowError'un en yaygın nedenidir. Özyinelemeyi önlemek için bir bayrak kilidi kullanılır.
Üç yöntemin her biri metin değişikliği yaşam döngüsünde kendi rolünü oynar. beforeTextChanged(CharSequence s, int start, int count, int after) yöntemi, değişiklikler uygulanmadan önce çağrılır. Dizgenin geçerli durumunu, değişikliğin başlangıç konumunu, silinen karakter sayısını ve eklenen karakter sayısını iletir. Burada, değişiklikten önce önceki değeri kaydedebilir veya koşulları kontrol edebilirsiniz.
onTextChanged yöntemi, karakterler zaten kaldırılmış ancak yenileri henüz eklenmemişken, değişiklik sırasında çağrılır. Parametreler: silme işleminden sonraki metin, başlangıç konumu, silinen karakter sayısı ve eklenen karakter sayısı. Bu yöntem, animasyon veya günlük kaydı için uygundur, ancak gerçek son metinle çalışmak için uygun değildir — henüz birleştirilmemiştir.
afterTextChanged yöntemi en çok talep edilen yöntemdir. Bir Editable nesnesi alır ve değişiklikler tamamen uygulandıktan sonra çağrılır. Bu yöntemde, alanın son değerini okuyabilir, doğrulama yapabilir, UI'yi güncelleyebilir ve metni değiştirebilirsiniz (özyineleme nedeniyle dikkatli olun).
Pratik bir örnek, her metin değişikliğinde güncellenen bir giriş alanı için karakter sayacıdır. Bu tür bir öğe, geri bildirim formlarında, gönderilerde ve uzunluk sınırı olan mesajlarda sıkça bulunur. TextWatcher aracılığıyla uygulama birkaç satır alır ve üçüncü taraf kütüphane gerektirmez.
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"
}
})
Örnekte, afterTextChanged yöntemi, Editable türündeki s parametresi aracılığıyla alanın geçerli içeriğini alır. Metin uzunluğu ayrı bir TextView'de güncellenir. Bu durumda, yalnızca counterText değiştirilir, EditText'in kendisi değil, bu nedenle döngü oluşmaz. 200 karakterlik bir sınır için, aşım sonrasında girişi ek olarak engelleyebilirsiniz.
beforeTextChanged ve onTextChanged yöntemleri boş kalır, çünkü uzunluk sayımı için son durum yeterlidir. Her değişikliği günlüğe kaydetmeniz gerekiyorsa, onTextChanged'e kod eklenebilir. Bu esneklik, TextWatcher'ı herhangi bir metin girişi senaryosu için evrensel bir araç haline getirir.
Gerçek zamanlı doğrulama, UX'i önemli ölçüde iyileştirir: kullanıcı, gönder düğmesine tıkladıktan sonra değil, hatalı bir değer girdikten hemen sonra bir hata görür. TextWatcher, e-posta, şifre, telefon numarası ve diğer alanların anında kontrolünü sağlar. Sonuç, EditText'te setError aracılığıyla veya bir hata mesajı içeren ayrı bir TextView aracılığıyla görüntülenir.
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(...) {}
})
}
Örnek, e-postayı kontrol etmek için Android SDK'dan yerleşik Patterns.EMAIL_ADDRESS'i kullanır. Metin boş değilse ve desenle eşleşmezse, error özelliği aracılığıyla alanda bir hata ayarlanır. Doğru girişte hata temizlenir. Boş bir alanda doğrulama çalıştırmamak önemlidir — kullanıcı henüz yazmaya başlamamış olabilir ve bir hata mesajı erken olur.
Şifreler ve telefon numaraları için özel düzenli ifadeler veya uzmanlaşmış kütüphaneler kullanılır. Örneğin, şifre karmaşıklığını kontrol etmek için rakam, büyük ve küçük harf sayısını sayabilirsiniz. TextWatcher, şifre gücü göstergesini gerçek zamanlı olarak güncellemeyi sağlar ve bu da kayıt dönüşümünü olumlu etkiler.
İlk ve en kritik hata özyinelemeli çağrıdır. afterTextChanged içinde aynı EditText'in metnini değiştirirseniz (s.clear(), s.append() veya s.insert() aracılığıyla), TextWatcher tekrar tetiklenir. Bu, StackOverflowError ile sonuçlanan sonsuz bir döngü oluşturur. Çözüm, bir isUpdating bayrak kilidi kullanmak veya metnin gerçekten değişip değişmediğini kontrol etmektir.
İkinci yaygın sorun bellek sızıntısıdır. TextWatcher, anonim bir sınıf aracılığıyla Activity veya Fragment'a örtük bir referans tutar. Görünüm yok edildiğinde dinleyici kaldırılmazsa, çöp toplayıcı belleği serbest bırakamaz. Çözüm, yaşam döngüsü bileşenlerini kullanmak veya onDestroyView'da açıkça removeTextChangedListener'ı çağırmaktır.
Üçüncü hata, yanlış yöntemi kullanmaktır. Bazı geliştiriciler, afterTextChanged'i beklemeden onTextChanged'de son doğrulamayı yapar. onTextChanged'de metin henüz tam olarak güncellenmemiştir ve son değeri okumak yanlış veriler döndürebilir. Doğru yaklaşım, son metni okuma ve kontrol etme mantığının tamamının afterTextChanged'de olmasıdır.
| Yöntem | Çağrı zamanı | Amaç | Son metin okunabilir mi? |
|---|---|---|---|
| beforeTextChanged | Değişiklikten önce | Önceki durumu kaydet | Evet |
| onTextChanged | Değişiklik sırasında | Günlük kaydı, animasyon | Hayır |
| afterTextChanged | Değişiklikten sonra | Doğrulama, sayma, UI güncelleme | Evet |
Dördüncü hata, TextWatcher'ın birden çok kez eklenmesidir. Aynı EditText için addTextChangedListener birden çok kez çağrılırsa, tüm dinleyiciler aynı değişikliği işler. Dinamik Görünüm ekleme içeren formlarda, bu yinelenen kontrollere ve öngörülemeyen davranışa yol açar. Dinleyicinin daha önce eklenip eklenmediğini her zaman kontrol edin veya tek bir örnek kullanın.
Sıkça Sorulan Sorular
OnTextChanged, yeni karakterler henüz eklenmemişken, metin değişikliği anında çağrılır. Bu yöntem animasyon ve günlük kaydı için uygundur. AfterTextChanged, değişiklikler tamamen uygulandıktan sonra çağrılır ve Editable parametresi aracılığıyla son metne erişim sağlar. Doğrulama ve değer okuma için afterTextChanged'i kullanın.
afterTextChanged içinde metni değiştirmeden önce true olarak ayarlanan Boolean türünde bir bayrak kilidi kullanın. Yöntemin başında bayrağı kontrol edin: true ise — çıkın. Alternatif olarak, eski ve yeni değerleri karşılaştırın ve yalnızca gerçek bir fark olduğunda metni değiştirin.
Evet, kesinlikle. Anonim TextWatcher sınıfı, bir kapatma yoluyla Activity'ye bir referans tutar. Dinleyici kaldırılmazsa, Activity çöp toplayıcı tarafından toplanamaz. Fragment için onDestroyView'da veya Activity için onDestroy'de her zaman removeTextChangedListener'ı çağırın.
Evet, ancak dikkatli olun. RecyclerView'da ViewHolder'lar yeniden kullanılır ve önceki bir konumdan gelen TextWatcher etkin kalabilir. onBindViewHolder yönteminde yenisini ayarlamadan önce eski TextWatcher'ı her zaman kaldırın. Dinleyici referansını saklamak için etiketler veya ayrı ViewHolder alanları kullanın.
Arama alanı için, debounce (gecikme) ile birlikte afterTextChanged'i kullanın. Her yeni metin değişikliğinde sıfırlanan 300-500 ms'lik bir zamanlayıcı uygulayın. Bu, her tuş vuruşunda sunucuya istek göndermeyi önler ve API yükünü azaltır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun