You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 8.0点击带EditText的FAB触发IndexOutOfBoundsException问题

Android 8.0上EditText.replace()触发IndexOutOfBoundsException的解决方案

看起来你在Android 8.0(API 26)上碰到了一个针对性的索引越界问题,我来帮你捋捋原因和修复办法。

问题根源分析

从你提供的堆栈跟踪和代码来看,异常是在SpannableStringBuilder.checkRange()中抛出的,对应代码第116行的field.getText().replace(at, at + 1, view.getText())。这说明你尝试替换的文本范围(at到at+1)超出了当前EditText文本的实际长度。

为什么这个问题只在Android 8.0出现?不同版本的Android系统对EditText的光标位置、文本编辑的内部处理逻辑有差异:在8.0上,当EditText的文本已经填满(比如达到你定义的FIELD_LENGTH),或者光标处于文本末尾时,getSelectionStart()返回的值可能等于文本长度,这时候at+1就会超出文本的有效索引范围(索引从0到length-1),触发越界异常。而更高版本的Android可能已经在系统层面做了索引边界的自动修正,所以不会出现这个问题。

修复方案

方案1:添加索引合法性检查,区分替换和追加逻辑

在执行replace操作前,先判断光标位置是否在文本范围内,光标在末尾时直接追加文本而不是替换:

void onClick(TextView view) {
    if (mFocusGrabber.isFocused()) return;
    EditText field = getFocusedField();
    int at = field.getSelectionStart();
    CharSequence inputText = view.getText();
    Editable editableContent = field.getText();
    int currentTextLength = editableContent.length();

    // 检查索引是否合法,避免越界
    if (at < currentTextLength) {
        // 光标在文本中间,替换指定位置的字符
        editableContent.replace(at, at + 1, inputText);
    } else {
        // 光标在文本末尾,直接追加内容
        editableContent.append(inputText);
    }

    // 更新光标位置,确保不超出文本长度
    int newCursorPos = at + 1;
    field.setSelection(Math.min(newCursorPos, editableContent.length()));

    // 原有后续逻辑保持不变
    if (field.getSelectionStart() == FIELD_LENGTH) {
        View next = field.focusSearch(View.FOCUS_RIGHT);
        if (next != null) {
            next.requestFocus();
            if (next instanceof EditText) {
                ((EditText) next).setSelection(0);
            }
        }
    }
}

方案2:预先修正光标位置的边界

在获取selectionStart后,先做一次边界修正,确保它不会超过文本长度:

void onClick(TextView view) {
    if (mFocusGrabber.isFocused()) return;
    EditText field = getFocusedField();
    Editable editableContent = field.getText();
    int currentTextLength = editableContent.length();
    // 修正光标位置,确保在0到currentTextLength之间
    int at = Math.max(0, Math.min(field.getSelectionStart(), currentTextLength));
    
    CharSequence inputText = view.getText();
    if (at < currentTextLength) {
        editableContent.replace(at, at + 1, inputText);
    } else {
        editableContent.append(inputText);
    }

    field.setSelection(Math.min(at + 1, editableContent.length()));

    // 原有后续逻辑...
}

额外建议

你也可以检查一下FIELD_LENGTH的逻辑,确保当EditText文本达到最大长度时,要么禁用数字按钮,要么拦截点击事件,从源头上避免用户在文本已满时继续输入,这样也能减少这类异常的发生。

内容的提问来源于stack exchange,提问作者Fatih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:41:16