TextWatcher — Android interfeysidir ki, EditText və digər TextView-lərdə mətn dəyişikliklərini real vaxtda izləməyə imkan verir. Tərtibatçı üç mərhələdə bildiriş alır: dəyişiklikdən əvvəl, dəyişiklik zamanı və mətn məzmunu dəyişdikdən sonra. Android Developers, 2026 məlumatına görə, TextWatcher əksər tətbiqlərdə girişin yoxlanılması, simvolların sayılması, avtomatik tamamlama ilə axtarışın tətbiqi və mətnin dinamik formatlaşdırılması üçün istifadə olunur. İnterfeys hər düymə vurulmasına dərhal reaksiya tələb olunan formalarda əvəzedilməzdir.
Əsas məqamlar
TextWatcher — android.text paketindən olan interfeysdir ki, Editable obyektlərində mətn dəyişiklikləri barədə tətbiqə məlumat verir. Hər simvol daxil edilməsi, silinməsi və ya dəyişdirilməsi zamanı TextWatcher ardıcıl olaraq üç metodu çağırır, dəyişikliklərin yeri haqqında məlumat ötürür. Bu, tərtibatçıya istifadəçinin hərəkətlərinə dərhal — əlavə düymələr və ya tetikleyicilər olmadan — reaksiya verməyə imkan verir.
Əsas istifadə ssenarilərinə sahələrin real vaxtda yoxlanılması daxildir: hər simvol daxil edildikdə e-poçtun yoxlanılması, uzunluğu məhdud olan sahədə qalan simvolların sayılması, debounce vasitəsilə gecikmiş sorğu göndərmə ilə axtarışın tətbiqi. TextWatcher həmçinin daxilolmanın formatlaşdırılması üçün istifadə olunur — məsələn, telefon nömrəsində avtomatik boşluqların yerləşdirilməsi və ya tarix üçün maskanın əlavə edilməsi.
Android Developers məlumatına görə, TextWatcher formalarla işləyən tətbiqlərin 70%-də mövcuddur. Material Design Components və TextInputEditText kimi kitabxanalar xəta vəziyyətini idarə etmək və sayğacları göstərmək üçün TextWatcher-dən daxili istifadə edir. Bu interfeysin işini başa düşmək hər bir Android tərtibatçısı üçün zəruridir.
TextWatcher istənilən TextView və ya EditText obyektinə addTextChangedListener metodu vasitəsilə qoşulur. İstifadəçi simvol daxil etdikdə və ya sildikdə, Android əvvəlcə beforeTextChanged, sonra onTextChanged və nəhayət afterTextChanged-i çağırır. Hər metodun parametrlərində dəyişdirilən diapazon haqqında məlumat ötürülür: başlanğıc mövqe, silinmiş simvolların sayı və əlavə edilmiş simvolların sayı.
Başa düşmək vacibdir ki, afterTextChanged çağırıldıqdan sonra Editable obyekti artıq aktual dəyəri ehtiva edir. Buna görə də afterTextChanged-də sahənin son mətnini yoxlamaq rahatdır. Bu ana qədər məlumatlar hələ tam yenilənməmişdir. Tərtibatçılar tez-tez metodların təyinatını qarışdırır və son yoxlama üçün onTextChanged-dən istifadə edirlər, halbuki düzgün seçim afterTextChanged-dir.
Hər simvol daxil edilməsi, dəyişdirilməsi və ya silinməsi zamanı çağırış zənciri tam şəkildə yerinə yetirilir. Lakin afterTextChanged daxilində mətn dəyişdirilərsə (clear, append, insert vasitəsilə), TextWatcher rekursiv işə düşəcək. Bu, Android formalarında StackOverflowError-un ən çox yayılmış səbəbidir. Rekursiyanın qarşısını almaq üçün bloklama bayrağından istifadə olunur.
Üç metodun hər biri mətn dəyişikliyinin həyat dövründə öz rolunu oynayır. beforeTextChanged(CharSequence s, int start, int count, int after) metodu dəyişikliklər tətbiq edilməzdən əvvəl çağırılır. O, sətrin cari vəziyyətini, dəyişikliyin başlanğıc mövqeyini, silinən simvolların sayını və əlavə edilənlərin sayını ötürür. Burada əvvəlki dəyəri saxlamaq və ya dəyişiklikdən əvvəl şərtləri yoxlamaq olar.
onTextChanged metodu dəyişiklik zamanı, simvollar artıq silindikdə, lakin yeniləri hələ daxil edilmədikdə çağırılır. Parametrlər: silinmədən sonra mətn, başlanğıc mövqe, silinmiş simvolların sayı və əlavə edilənlərin sayı. Bu metod animasiya və ya logging üçün əlverişlidir, lakin cari son mətnlə işləmək üçün deyil — o hələ tamamlanmayıb.
afterTextChanged metodu ən çox tələb olunandır. O, Editable obyekti alır və dəyişikliklər tam tətbiq edildikdən sonra çağırılır. Bu metoddan sahənin son dəyərini oxumaq, yoxlama aparmaq, UI-ni yeniləmək və mətni dəyişdirmək (rekursiya səbəbindən ehtiyatla) olar.
Praktiki nümunə — mətn hər dəyişdikdə yenilənən simvol sayğacı daxilolma sahəsi üçün. Belə element tez-tez əlaqə formalarında, yazılarda və uzunluğu məhdud olan mesajlarda rast gəlinir. TextWatcher vasitəsilə tətbiq bir neçə sətir çəkir və üçüncü tərəf kitabxanaları tələb etmir.
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"
}
})
Nümunədə afterTextChanged metodu s parametri (Editable növü) vasitəsilə sahənin cari məzmununu alır. Mətnin uzunluğu ayrıca TextView-də yenilənir. Bu halda rekursiyanın qarşısını almaq üçün yalnız counterText dəyişdirilir, EditText-in özü deyil, ona görə də dövr yaranmır. 200 simvol limiti olduqda, hədd aşıldıqdan sonra daxilolmanı bloklamaq olar.
beforeTextChanged və onTextChanged metodları boş qalır, çünki uzunluğu hesablamaq üçün son vəziyyət kifayətdir. Hər dəyişikliyi qeyd etmək lazım gələrsə, kod onTextChanged-ə əlavə edilə bilər. Bu çeviklik TextWatcher-i mətn daxilolması ilə işin istənilən ssenarisi üçün universal alət edir.
Real vaxtda yoxlama UX-i əhəmiyyətli dərəcədə yaxşılaşdırır: istifadəçi səhv dəyər daxil etdikdən dərhal sonra xətanı görür, göndərmə düyməsini basdıqdan sonra yox. TextWatcher e-poçt, şifrə, telefon nömrəsi və digər sahələrin ani yoxlanılmasını təmin edir. Nəticə EditText-də setError vasitəsilə və ya ayrıca TextView-də xəta mesajı ilə göstərilir.
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(...) {}
})
}
Nümunədə e-poçtu yoxlamaq üçün Android SDK-dan daxili Patterns.EMAIL_ADDRESS istifadə olunur. Mətn boş deyilsə və nümunəyə uyğun gəlmirsə, sahəyə error xassəsi vasitəsilə xəta təyin edilir. Düzgün daxiletmə zamanı xəta təmizlənir. Boş sahədə yoxlamanı işə salmamaq vacibdir — istifadəçi hələ daxiletməyə başlamamış ola bilər və xəta mesajı vaxtından əvvəl olacaq.
Şifrələr və telefon nömrələri üçün fərdi regex ifadələri və ya ixtisaslaşmış kitabxanalar istifadə olunur. Məsələn, şifrənin mürəkkəbliyini yoxlamaq üçün rəqəmlərin, böyük və kiçik hərflərin sayını hesablamaq olar. TextWatcher şifrə mürəkkəbliyi göstəricisini real vaxtda yeniləməyə imkan verir ki, bu da qeydiyyat konversiyasına müsbət təsir edir.
Birinci və ən kritik səhv — rekursiv çağırış. afterTextChanged daxilində eyni EditText-in mətni dəyişdirilərsə (s.clear(), s.append() və ya s.insert() vasitəsilə), TextWatcher yenidən işə düşəcək. Bu, StackOverflowError ilə nəticələnən sonsuz dövr yaradır. Həll yolu — isUpdating bloklama bayrağından istifadə etmək və ya mətnin həqiqətən dəyişib-dəyişmədiyini yoxlamaqdır.
İkinci geniş yayılmış problem — yaddaş sızması. TextWatcher anonim sinif vasitəsilə Activity və ya Fragment-ə gizli istinad saxlayır. View məhv edilərkən listener silinməzsə, garbage collector yaddaşı boşalda bilməyəcək. Həll yolu — həyat dövrü komponentlərindən istifadə etmək və ya onDestroyView-də removeTextChangedListener-i açıq şəkildə çağırmaqdır.
Üçüncü səhv — yanlış metoddan istifadə. Bəzi tərtibatçılar afterTextChanged-i gözləmədən onTextChanged-də son yoxlama aparırlar. onTextChanged-də mətn hələ tam yenilənməyib və son dəyərin oxunması səhv məlumat qaytara bilər. Düzgün yanaşma — son mətni oxumaq və yoxlamaq üçün bütün məntiqi afterTextChanged-də yerləşdirməkdir.
| Metod | Çağırılma anı | Təyinat | Son mətni oxumaq olar? |
|---|---|---|---|
| beforeTextChanged | Dəyişiklikdən əvvəl | Əvvəlki vəziyyətin saxlanması | Bəli |
| onTextChanged | Dəyişiklik zamanı | Logging, animasiya | Xeyr |
| afterTextChanged | Dəyişiklikdən sonra | Yoxlama, sayma, UI yeniləmə | Bəli |
Dördüncü səhv — TextWatcher-in çoxsaylı əlavə edilməsi. addTextChangedListener bir EditText üçün bir neçə dəfə çağırılıbsa, bütün listener-lər eyni dəyişikliyi emal edəcək. View-lərin dinamik əlavə edildiyi formalarda bu, yoxlamaların təkrarlanmasına və gözlənilməz davranışa səbəb olur. Həmişə listener-in əvvəllər əlavə edilib-edilmədiyini yoxlayın və ya vahid instansiyadan istifadə edin.
Tez-tez verilən suallar
OnTextChanged mətn dəyişikliyi anında çağırılır, yeni simvollar hələ əlavə edilməmişdir. Bu metod animasiya və logging üçün uyğundur. AfterTextChanged dəyişikliklər tam tətbiq edildikdən sonra çağırılır və Editable parametri vasitəsilə son mətnə giriş imkanı verir. Yoxlama və dəyər oxumaq üçün afterTextChanged-dən istifadə edin.
afterTextChanged daxilində mətni dəyişməzdən əvvəl true vəziyyətinə təyin olunan Boolean tipli bloklama bayrağından istifadə edin. Metodun əvvəlində bayrağı yoxlayın: əgər true-dirsə — çıxın. Alternativ olaraq köhnə və yeni dəyəri müqayisə edib mətni yalnız həqiqi fərq olduqda dəyişmək olar.
Bəli, mütləq. TextWatcher-in anonim sinfi closure vasitəsilə Activity-yə istinad saxlayır. Listener silinməzsə, Activity garbage collector tərəfindən toplana bilməz. Fragment üçün onDestroyView-də, Activity üçün onDestroy-də həmişə removeTextChangedListener-i çağırın.
Bəli, lakin ehtiyatla. RecyclerView-də ViewHolder-lər təkrar istifadə olunur və əvvəlki mövqedən TextWatcher aktiv qala bilər. onBindViewHolder metodunda yeni TextWatcher quraşdırmazdan əvvəl həmişə köhnəni silin. Listener-ə istinad saxlamaq üçün tag-lərdən və ya ViewHolder-in ayrıca sahələrindən istifadə edin.
Axtarış sahəsi üçün debounce (gecikmə) ilə birlikdə afterTextChanged istifadə edin. Hər yeni mətn dəyişikliyində sıfırlanan 300-500 ms-lik taymer tətbiq edin. Bu, hər düymə vurulmasında serverə sorğu göndərilməsinin qarşısını alır və API yükünü azaldır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun