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

Android TextView调用setHint时偶发IndexOutOfBoundsException问题求助

关于TextView设置Hint触发IndexOutOfBoundsException的问题分析与解决

之前为解决TextView(EditText)因Hint导致的宽度适配问题,采用对应方案后,极低概率触发如下越界异常:

java.lang.IndexOutOfBoundsException: setSpan (-1 ... -1) starts before 0
    at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1331)
    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:685)
    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:677)
    at android.text.Selection.setSelection(Selection.java:94)
    at android.text.Selection.setSelection(Selection.java:78)
    at android.text.Selection.setSelection(Selection.java:153)
    at android.widget.Editor$VigourInsertionHandleView.updateSelectPosition(Editor.java:7731)
    at android.widget.Editor$VigourInsertionHandleView.endFollowHandle(Editor.java:7643)
    at android.widget.Editor$VigourInsertionHandleView.onTouchEvent(Editor.java:7558)
    at android.view.View.dispatchTouchEvent(View.java:15275)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3148)
    at android.view.ViewGroup.cancelAndClearTouchTargets(ViewGroup.java:2981)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3984)
    at android.view.ViewRootImpl.dispatchDetachedFromWindow(ViewRootImpl.java:5754)
    at android.view.ViewRootImpl.doDie(ViewRootImpl.java:9224)
    at android.view.ViewRootImpl.die(ViewRootImpl.java:9200)
    at android.view.WindowManagerGlobal.removeViewLocked(WindowManagerGlobal.java:516)
    at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:457)
    at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:216)
    at android.widget.PopupWindow.dismissImmediate(PopupWindow.java:2444)
    at android.widget.PopupWindow.dismiss(PopupWindow.java:2378)
    at android.widget.Editor$HandleView.dismiss(Editor.java:5413)
    at android.widget.Editor$InsertionHandleView.dismiss(Editor.java:6278)
    at android.widget.Editor$HandleView.hide(Editor.java:5423)
    at android.widget.Editor$InsertionPointCursorController.hide(Editor.java:7020)
    at android.widget.Editor.hideInsertionPointCursorController(Editor.java:1102)
    at android.widget.Editor.prepareCursorControllers(Editor.java:1084)
    at android.widget.TextView.nullLayouts(TextView.java:9513)
    at android.widget.TextView.checkForRelayout(TextView.java:10354)
    at android.widget.TextView.setHintInternal(TextView.java:6917)
    at android.widget.TextView.setHint(TextView.java:6906)

异常定性

这是Android系统底层的竞态Bug:从堆栈轨迹可见,调用TextView.setHint()触发视图重排时,系统同时在处理插入光标控制器的隐藏逻辑,此时光标位置已变为无效的-1,导致Selection.setSelection()传入了非法的索引范围,最终抛出越界异常。

解决方案

1. 捕获异常直接规避

自定义EditText或TextView,重写setHint()方法包裹异常捕获,避免崩溃:

@Override
public void setHint(CharSequence hint) {
    try {
        super.setHint(hint);
    } catch (IndexOutOfBoundsException ignored) {
        // 极低概率触发的系统异常,无需额外处理
    }
}

2. 优化原Hint宽度适配方案

如果原方案依赖动态切换Hint(比如先设空再恢复),可调整逻辑减少系统Bug触发概率:

  • 避免在触摸事件未结束、视图即将销毁等不稳定状态下调用setHint()
  • 改用静态布局方案:比如给TextView设置android:minWidth,或用TextUtils.concat拼接占位符文本,替代动态切换Hint的方式

3. 延迟操作规避竞态

在需要设置Hint时,通过post()延迟执行,确保视图处于稳定状态:

textView.post(() -> {
    textView.setHint("你的提示文本");
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:26:36