Reputation: 133
In my app I want to track the input in an EditText
. Each time the user modifies a character in the EditText
I want to track:
I use TextWatcher
in order to achieve this. My approach has been working fine till now. But recently I have had 3 crashes with IndexOutOfBoundsException
in my production app. One thing that I have noted is that all the crashes occurred on a Galaxy S7 with OS version 6.0.1.
I am trying to figure out a good way to understand and fix this crash. Please refer the code below
public class EditTextMonitor extends Activity implements TextWatcher {
private EditText etInputText;
private int deleteCharIndex = -1, addCharIndex = -1;
private char deleteChar;
private boolean wasCharDeleted;
private String prevCharSeq = "";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
etInputText = (EditText) findViewById(R.id.etInputText);
}
// Add TextChangedListener here to prevent call to text watcher methods upon switching
// orientation
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
etInputText.addTextChangedListener(this);
}
/*
This method is called to notify you that, within s, the count characters beginning at
start have just replaced old text that had length before. It is an error to attempt to
make changes to s from this callback.
*/
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
/*
This method is called to notify you that, within s, the count characters beginning at start
are about to be replaced by new text with length after.
It is an error to attempt to make changes to s from this callback.
*/
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// if count > after then its a char delete cause the no. of chars in 's'
// will decrease when the text change is complete.
// If count < after
// then its a char addition cause the no. of chars in 's'
// will increase when the text change is complete.
if (count > after) {
// CHARACTER DELETION
// As 'count' is no. of chars being replaced from 'start' by
// 'after' no. of chars, (start+count)-1 will be the index of the
// char that that will be deleted.
deleteCharIndex = (start + count) - 1;
deleteChar = s.charAt(deleteCharIndex);
wasCharDeleted = true;
} else if (count < after) {
// CHARACTER ADDITION
// As 'count' is no. of chars being replaced from 'start' by
// 'after' no. of chars, (start+after)-1 will will be the index of the
// char that will be added.
wasCharDeleted = false;
addCharIndex = (start + after) - 1;
} else {
// Extra call to the text changed method with no change in 's'.
// Android framework bug??
wasCharDeleted = false;
Log.d(TAG, "------EXTRA CALL TO BEFORETEXTCHANGED------");
}
}
@Override
public void afterTextChanged(Editable s) {
// Don't process if redundant call to afterTextChanged method.
// A framework bug??
if (!prevCharSeq.equals(s.toString())) {
if (wasCharDeleted) {
// handle char delete
if (deleteChar == 'x'
&& (s.length() == 0 || s.charAt(deleteCharIndex - 1) == ' ')) {
// Business logic to deal with the case where the deleted char was an independent 'x'
} else {
// Business logic to deal with the case where deleted char was anything other than an independent 'x'.
}
} else {
// handle char addition
***if (s.charAt(addCharIndex) == 'x'// CRASH OCCURS ON THIS LINE <-----------------***
&& (s.length() == 1 || s.charAt(addCharIndex - 1) == ' ')) {
// Business logic to deal with the case where added char is an independent 'x'
} else {
// Business logic to deal with the case where added char is anything other than an independent 'x'
}
}
}
prevCharSeq = s.toString();
}
}
The 3 crashes so far have been:
java.lang.IndexOutOfBoundsException: charAt: 24 >= length 23
java.lang.IndexOutOfBoundsException: charAt: 202 >= length 198
java.lang.IndexOutOfBoundsException: charAt: 1 >= length 1
Looking at the indices in the exception, I assume that the addCharIndex
is not getting calculated correctly. This means that either my understanding of the parameters of beforeTextChanged
is incorrect or the TextWatcher
methods are not being called in the expected order or they are called multiple times with updated arguments which is messing up my logic to calculate the addCharIndex
in beforeTextChanged
.
Any help and insight on how to address this issue will be appreciated.
Thanks.
Upvotes: 0
Views: 538
Reputation: 4759
It's not a device issue. It's a logic issue.
Your problem actually occurs on the line before that. Because when you delete characters you don't update your addCharIndex
. If the previous index was 10 and you delete 8 characters, your index is still 10 but you only have a length of 2.
If you type in xd
into your input then delete the x
you'll get a crash as a result of indexOutOfBoundsException
that's because your if statement does the following:
s.charAt(deleteCharIndex - 1) == ' '
but since you've deleted the x
character your length is now 1 but you're checking for 0 OR the above statement which is how you get your error. If you didn't know if you have an OR (||) in an if statement, it will check every condition until it hits a true result.
There are many ways to fix it, one way is to check that s.length() > 1
this way when you do deleteCharIndex - 1
the lowest point you can hit is 0.
Upvotes: 3