Search code examples
androidandroid-textwatcher

Inconsistent onTextChanged() behaviour


I wrote the code below to figure out how onTextChanged() method works:

override fun onTextChanged(string: CharSequence?, start: Int, before: Int, count: Int) {
                Log.d(TAG, "onTextChanged triggered.")
                Log.d(TAG, "string = $string")
                Log.d(TAG, "start = $start")
                Log.d(TAG, "before = $before")
                Log.d(TAG, "count = $count")
                Log.d(TAG, "____________________________________________________________")

Here's what I noticed: when I'm typing letters only, the count is pretty straightforward:

onTextChanged triggered.
string = a
start = 0
before = 0
count = 1
____________________________________________________________
onTextChanged triggered.
string = aa
start = 0
before = 1
count = 2
____________________________________________________________
onTextChanged triggered.
string = aaa
start = 0
before = 2
count = 3
____________________________________________________________
onTextChanged triggered.
string = aaaa
start = 0
before = 3
count = 4
____________________________________________________________
onTextChanged triggered.
string = aaaaa
start = 0
before = 4
count = 5
____________________________________________________________

Now if I add 3 (or more) digits and then keep on typing letters, this is what happens:

onTextChanged triggered.
string = aaaaa2
start = 0
before = 5
count = 6
____________________________________________________________
onTextChanged triggered.
string = aaaaa22
start = 0
before = 6
count = 7
____________________________________________________________
onTextChanged triggered.
string = aaaaa222
start = 0
before = 7     
count = 8
____________________________________________________________
onTextChanged triggered.
string = aaaaa222
start = 0
before = **8**      <---- This is when it gets funny
count = **8**
____________________________________________________________
onTextChanged triggered.
string = aaaaa222a
start = 8
before = 0
count = 1
____________________________________________________________
onTextChanged triggered.
string = aaaaa222aa
start = 9
before = 0
count = 1
 ____________________________________________________________
onTextChanged triggered.
string = aaaaa222aaa
start = 10
before = 0
count = 1
____________________________________________________________
onTextChanged triggered.
string = aaaaa222aaaa
start = 11
before = 0
count = 1
____________________________________________________________
onTextChanged triggered.
string = aaaaa222aaaaa
start = 12
before = 0
count = 1
____________________________________________________________

To me it seems like inputing 3 digits somehow changes the TextWatcher's behaivior making it treat everything that comes after as a Char rather than a CharSequence.

Is there an explanation to this behaviour?


Solution

  • While I don't have an explanation why it happens with 3 digits, I found out that there is no guarantee when offesets will be invalidated at all. Check this this

    "You are not told where the change took place because other afterTextChanged() methods may already have made other changes and invalidated the offsets. But if you need to know here, you can use Spannable#setSpan in onTextChanged(CharSequence, int, int, int) to mark your place and then look up from here where the span ended up."

    One possible implemetation of TextWatcher would be this one. That way you will have the proper begin and end indexes.