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
相关产品推荐
相关产品推荐

