java - TextWatcher 中的 IndexOutOfBoundsException

标签 java android indexoutofboundsexception android-textwatcher

在我的应用程序中,我想跟踪 EditText 中的输入。每次用户修改 EditText 中的字符时,我想跟踪:

  1. 如果添加/删除了字符
  2. 添加/删除字符的索引以及
  3. 添加/删除了什么字符

我使用TextWatcher来实现这一点。到目前为止,我的方法一直运行良好。但最近我在生产应用程序中因 IndexOutOfBoundsException 发生了 3 次崩溃。我注意到的一件事是,所有崩溃都发生在操作系统版本 6.0.1 的 Galaxy S7 上。

我正在尝试找出一种好方法来理解和修复此崩溃。请引用以下代码

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();
    }
}

迄今为止发生的 3 次崩溃是:

java.lang.IndexOutOfBoundsException:  charAt: 24 >= length 23

java.lang.IndexOutOfBoundsException:  charAt: 202 >= length 198

java.lang.IndexOutOfBoundsException:  charAt: 1 >= length 1

查看异常中的索引,我假设 addCharIndex 未正确计算。这意味着我对 beforeTextChanged 参数的理解不正确,或者 TextWatcher 方法没有按预期顺序调用,或者使用更新的参数多次调用它们,这是搞乱了我在 beforeTextChanged 中计算 addCharIndex 的逻辑。

任何有关如何解决此问题的帮助和见解将不胜感激。

谢谢。

最佳答案

这不是设备问题。这是一个逻辑问题。

你的问题实际上就发生在之前的线路上。因为当您删除字符时,您不会更新 addCharIndex。如果之前的索引是 10,而你删除了 8 个字符,那么你的索引仍然是 10,但长度只有 2。

如果您在输入中输入xd,然后删除x,您将因indexOutOfBoundsException而崩溃,这是因为您的if 语句执行以下操作:

s.charAt(deleteCharIndex - 1) == ' '

但是由于您删除了 x 字符,您的长度现在为 1,但您正在检查 0 或上述语句,这就是您得到错误的方式。如果您不知道 if 语句中是否有 OR (||),它将检查每个条件,直到得出正确的结果。

有很多方法可以修复它,一种方法是在执行 deleteCharIndex - 1 最低点时检查 s.length() > 1能命中的是0。

关于java - TextWatcher 中的 IndexOutOfBoundsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42681639/

相关文章:

c# - Java 中的 .NET TripleDESCryptoServiceProvider 等价物

java - 如何在 java 中将 Progression 类重新设计为抽象和通用的?

Android Simple Cursor 弃用和类加载器

java - 单击按钮时在 ListView 的行内显示删除按钮 Android

java - 将数字分隔为 2 个数组 Java

java - 反转 HashMap 中的键值对

java - Java 中的空指针异常错误

android - 使用 Room 的父类的主键?

java - 摩尔斯电码转英语: ArrayIndexOutOfBoundsException

android - 如何修复 java.lang.ArrayIndexOutOfBoundsException : length=1; index=1