Reputation: 1016
I'm having an error I can't seem to wrap my head around. I'm writing an app that allows the user to send text from an EditText
to a TextView
. If the user makes a mistake, the user can hit the space key to bring the most recent text sent from the EditText
to the TextView
. This works sometimes, but other times, it gives me an IndexOutOfBounds
exception.
textInput is an EditText, back1,2,3 are the three most recent strings (with back1 the most recent)
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(count==1&&before==0&&s.toString().equals(" ")){
textInput.setText(back1);
}else if(s.toString().equals(back1 + " ")){
textInput.setText(back2);
}else if(s.toString().equals(back2 + " ")){
textInput.setText(back3); //causes error if back2 > back3
}
textInput.setSelection(textInput.getText().toString().length());
The above code checks if the user hit the space key, and if so, what to do with it. If the user pressed space on an empty EditText, they get the last thing they sent. If they hit space again, they get the next to last thing they sent, and so on. This is still a bit rough, but I hope you get the idea.
The OutOfBounds exception comes from taking a large item in the EditText
, hitting space, and setting the EditText
to a smaller string. I assumed it was because the cursor is at the end of the EditText
and could no longer be there when the text got smaller, so I tried adding textInput.setSelection(0)
right before the setText()
. That didn't help. I also tried setting the EditText
to setText("")
. That didn't work either. If I comment out the lines of setText(back#)
, everything works fine.
An example:
A user types in "hello", "hi" and "hey" in that order.
back3 = hello, back2 = hi, and back1 = hey.
Hitting space once will set the EditText to "hey"
A second tap will crash, since the setSpan(3...4) ends beyond length 2
, presumably because back 1 is larger than back2. It is supposed to set the text in the EditText
to "hi"
Upvotes: 0
Views: 4286
Reputation: 15280
From the TextWatcher
documentation:
public abstract void onTextChanged (CharSequence s, int start, int before, int count)
Since: API Level 1
This method is called to notify you that, within
s
, thecount
characters beginning atstart
have just replaced old text that had lengthbefore
. It is an error to attempt to make changes tos
from this callback.
(My emphasis.)
You should use afterTextChanged
instead if you want to change the text more in response to an existing change. Even in this case, your handler will be called re-entrantly when you change the text from afterTextChanged
, so use an extra precaution to make sure you won't get into an infinite loop, such as something like this:
public void afterTextChanged (Editable s) {
static boolean is_reentrant = false;
if (!is_reentrant) {
is_reentrant = true;
try {
// do stuff
} finally {
is_reentrant = false;
}
}
}
I haven't tested this exact snippet, but something like that will make your code only run if it's not already running. You don't need to worry about thread-safety in this case, because it's only being called from inside the same thread.
Upvotes: 3