TextWatcher는 EditText 및 기타 TextView의 텍스트 변경 사항을 실시간으로 추적할 수 있는 Android 인터페이스입니다. 개발자는 세 단계로 알림을 받습니다: 변경 전, 변경 중, 텍스트 콘텐츠 변경 후입니다. Android Developers, 2026에 따르면, TextWatcher는 대부분의 애플리케이션에서 입력 유효성 검사, 문자 수 계산, 자동 완성 검색 구현 및 동적 텍스트 서식 지정에 사용됩니다. 이 인터페이스는 키를 누를 때마다 즉각적인 반응이 필요한 양식에서 필수적입니다.
핵심 포인트
TextWatcher는 android.text 패키지의 인터페이스로, Editable 객체의 텍스트 변경 사항을 애플리케이션에 알립니다. 문자를 입력, 삭제 또는 바꿀 때마다 TextWatcher는 세 가지 메서드를 순차적으로 호출하여 변경 위치에 대한 정보를 전달합니다. 이를 통해 개발자는 추가 버튼이나 트리거 없이 사용자 작업에 즉시 대응할 수 있습니다.
주요 사용 사례에는 실시간 필드 유효성 검사가 포함됩니다: 각 문자 입력 시 이메일 확인, 길이 제한이 있는 필드의 남은 문자 수 계산, 디바운스를 통한 지연 요청 검색 구현. TextWatcher는 입력 서식 지정에도 사용됩니다 — 예를 들어, 전화번호에 자동으로 공백을 삽입하거나 날짜 마스크를 추가합니다.
Android Developers에 따르면, TextWatcher는 양식으로 작업하는 애플리케이션의 70%에 존재합니다. Material Design Components 및 TextInputEditText와 같은 라이브러리는 내부적으로 TextWatcher를 사용하여 오류 상태를 관리하고 카운터를 표시합니다. 이 인터페이스의 작동 방식을 이해하는 것은 모든 Android 개발자에게 필수적입니다.
TextWatcher는 addTextChangedListener 메서드를 통해 모든 TextView 또는 EditText 객체에 연결됩니다. 사용자가 문자를 입력하거나 삭제하면 Android는 먼저 beforeTextChanged를 호출하고, 그다음 onTextChanged, 마지막으로 afterTextChanged를 호출합니다. 각 메서드의 매개변수에는 변경된 범위에 대한 데이터가 포함됩니다: 시작 위치, 삭제된 문자 수 및 추가된 문자 수입니다.
afterTextChanged를 호출한 후 Editable 객체에는 이미 현재 값이 포함되어 있음을 이해하는 것이 중요합니다. 따라서 afterTextChanged에서 필드의 최종 텍스트를 확인하는 것이 편리합니다. 그 시점 이전에는 데이터가 아직 완전히 업데이트되지 않았습니다. 개발자는 종종 메서드의 목적을 혼동하여 최종 유효성 검사에 onTextChanged를 사용하지만, 올바른 선택은 afterTextChanged입니다.
각 문자 삽입, 바꾸기 또는 삭제 시 호출 체인이 완전히 실행되는 것이 보장됩니다. 그러나 afterTextChanged 내에서 텍스트가 변경되면(clear, append, insert 사용) TextWatcher가 재귀적으로 트리거됩니다. 이것이 Android 양식에서 StackOverflowError의 가장 일반적인 원인입니다. 재귀를 방지하기 위해 플래그 잠금이 사용됩니다.
세 가지 메서드는 각각 텍스트 변경 수명 주기에서 역할을 수행합니다. beforeTextChanged(CharSequence s, int start, int count, int after) 메서드는 변경 사항이 적용되기 전에 호출됩니다. 문자열의 현재 상태, 변경 시작 위치, 삭제되는 문자 수 및 추가되는 문자 수를 전달합니다. 여기에서 이전 값을 저장하거나 수정 전에 조건을 확인할 수 있습니다.
onTextChanged 메서드는 변경 중에 호출되며, 문자가 이미 제거되었지만 새 문자가 아직 삽입되지 않은 시점입니다. 매개변수: 삭제 후 텍스트, 시작 위치, 삭제된 문자 수 및 추가된 문자 수. 이 메서드는 애니메이션이나 로깅에 편리하지만, 실제 최종 텍스트 작업에는 적합하지 않습니다 — 아직 조립되지 않았습니다.
afterTextChanged 메서드가 가장 많이 사용됩니다. Editable 객체를 받으며 변경 사항이 완전히 적용된 후 호출됩니다. 이 메서드에서 필드의 최종 값을 읽고, 유효성 검사를 수행하고, UI를 업데이트하고, 텍스트를 변경할 수 있습니다(재귀 때문에 주의 필요).
실용적인 예는 텍스트가 변경될 때마다 업데이트되는 입력 필드용 문자 카운터입니다. 이러한 요소는 피드백 양식, 게시물 및 길이 제한이 있는 메시지에서 자주 볼 수 있습니다. TextWatcher를 통한 구현은 몇 줄만 필요하며 타사 라이브러리가 필요하지 않습니다.
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"
}
})
예제에서 afterTextChanged 메서드는 Editable 유형의 s 매개변수를 통해 필드의 현재 내용을 받습니다. 텍스트 길이는 별도의 TextView에서 업데이트됩니다. 이 경우 counterText만 수정되고 EditText 자체는 수정되지 않으므로 루프가 발생하지 않습니다. 200자 제한이 있는 경우 초과 후 입력을 추가로 차단할 수 있습니다.
beforeTextChanged 및 onTextChanged 메서드는 비어 있습니다. 길이 계산에는 최종 상태로 충분하기 때문입니다. 각 변경 사항을 로깅해야 하는 경우 onTextChanged에 코드를 추가할 수 있습니다. 이러한 유연성은 TextWatcher를 모든 텍스트 입력 시나리오에 대한 범용 도구로 만듭니다.
실시간 유효성 검사는 UX를 크게 향상시킵니다: 사용자는 제출 버튼을 클릭한 후가 아니라 잘못된 값을 입력한 즉시 오류를 확인할 수 있습니다. TextWatcher를 사용하면 이메일, 비밀번호, 전화번호 및 기타 필드를 즉시 확인할 수 있습니다. 결과는 EditText의 setError를 통해 또는 오류 메시지가 있는 별도의 TextView를 통해 표시됩니다.
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(...) {}
})
}
예제에서는 Android SDK의 내장 Patterns.EMAIL_ADDRESS를 사용하여 이메일을 확인합니다. 텍스트가 비어 있지 않고 패턴과 일치하지 않으면 error 속성을 통해 필드에 오류가 설정됩니다. 올바른 입력 시 오류가 지워집니다. 빈 필드에서 유효성 검사를 실행하지 않는 것이 중요합니다 — 사용자가 아직 입력을 시작하지 않았을 수 있으며 오류 메시지가 시기상조일 수 있습니다.
비밀번호 및 전화번호의 경우 사용자 정의 정규식이나 전문 라이브러리가 사용됩니다. 예를 들어, 비밀번호 복잡성을 확인하기 위해 숫자, 대문자 및 소문자의 수를 계산할 수 있습니다. TextWatcher를 사용하면 비밀번호 강도 표시기를 실시간으로 업데이트할 수 있으며, 이는 등록 전환에 긍정적인 영향을 미칩니다.
첫 번째이자 가장 중요한 실수는 재귀 호출입니다. afterTextChanged 내에서 동일한 EditText의 텍스트를 변경하면(s.clear(), s.append() 또는 s.insert() 사용) TextWatcher가 다시 트리거됩니다. 이것은 StackOverflowError로 끝나는 무한 루프를 만듭니다. 해결책은 isUpdating 플래그 잠금을 사용하거나 텍스트가 실제로 변경되었는지 확인하는 것입니다.
두 번째 일반적인 문제는 메모리 누수입니다. TextWatcher는 익명 클래스를 통해 Activity 또는 Fragment에 대한 암시적 참조를 유지합니다. View가 소멸될 때 리스너가 제거되지 않으면 가비지 컬렉터가 메모리를 해제할 수 없습니다. 해결책은 수명 주기 구성 요소를 사용하거나 onDestroyView에서 명시적으로 removeTextChangedListener를 호출하는 것입니다.
세 번째 실수는 잘못된 메서드 사용입니다. 일부 개발자는 afterTextChanged를 기다리지 않고 onTextChanged에서 최종 유효성 검사를 수행합니다. onTextChanged에서는 텍스트가 아직 완전히 업데이트되지 않았으며 최종 값을 읽으면 잘못된 데이터가 반환될 수 있습니다. 올바른 접근 방식은 최종 텍스트를 읽고 확인하는 모든 로직이 afterTextChanged에 있어야 한다는 것입니다.
| 메서드 | 호출 시점 | 목적 | 최종 텍스트를 읽을 수 있나요? |
|---|---|---|---|
| beforeTextChanged | 변경 전 | 이전 상태 저장 | 예 |
| onTextChanged | 변경 중 | 로깅, 애니메이션 | 아니요 |
| afterTextChanged | 변경 후 | 유효성 검사, 계산, UI 업데이트 | 예 |
네 번째 실수는 TextWatcher 중복 추가입니다. 동일한 EditText에 대해 addTextChangedListener가 여러 번 호출되면 모든 리스너가 동일한 변경을 처리합니다. 동적 View 추가가 있는 양식에서는 중복 검사와 예측할 수 없는 동작이 발생합니다. 리스너가 이미 추가되었는지 항상 확인하거나 단일 인스턴스를 사용하세요.
자주 묻는 질문
OnTextChanged는 새 문자가 아직 추가되지 않은 텍스트 변경 시점에 호출됩니다. 이 메서드는 애니메이션 및 로깅에 적합합니다. AfterTextChanged는 변경이 완전히 적용된 후에 호출되며 Editable 매개변수를 통해 최종 텍스트에 대한 액세스를 제공합니다. 유효성 검사 및 값 읽기에는 afterTextChanged를 사용하세요.
afterTextChanged 내에서 텍스트를 변경하기 전에 true로 설정되는 Boolean 유형의 플래그 잠금을 사용하세요. 메서드 시작 부분에서 플래그를 확인합니다. true이면 종료합니다. 또는 이전 값과 새 값을 비교하고 실제 차이가 있을 때만 텍스트를 변경합니다.
네, 반드시 필요합니다. 익명 TextWatcher 클래스는 클로저를 통해 Activity에 대한 참조를 유지합니다. 리스너가 제거되지 않으면 Activity를 가비지 수집할 수 없습니다. Fragment의 onDestroyView 또는 Activity의 onDestroy에서 항상 removeTextChangedListener를 호출하세요.
네, 하지만 주의가 필요합니다. RecyclerView에서는 ViewHolders가 재사용되며 이전 위치의 TextWatcher가 활성 상태로 남을 수 있습니다. onBindViewHolder 메서드에서 새 TextWatcher를 설정하기 전에 항상 이전 TextWatcher를 제거하세요. 리스너 참조를 저장하려면 태그나 별도의 ViewHolder 필드를 사용하세요.
검색 필드에는 디바운스(지연)와 함께 afterTextChanged를 사용하세요. 각 텍스트 변경 시 재설정되는 300-500ms 타이머를 구현합니다. 이렇게 하면 키를 누를 때마다 서버에 요청을 보내는 것을 방지하고 API 부하를 줄일 수 있습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.