调用TextView getLineEnd(4)抛出ArrayIndexOutOfBoundsException异常
问题描述
为TextView配置android:maxLines="5"属性,在确认目标控件承载文本长度足够达到5行及以上的场景下,调用getLineEnd(4)方法抛出ArrayIndexOutOfBoundsException异常,相关信息如下:
异常日志
06-12 02:50:42.256 30175 30175 E ErrorPageActivity: java.lang.ArrayIndexOutOfBoundsException: length=27; index=30 06-12 02:50:42.256 30175 30175 E ErrorPageActivity: at android.text.StaticLayout.getLineStart(StaticLayout.java:1151) 06-12 02:50:42.256 30175 30175 E ErrorPageActivity: at android.text.Layout.getLineEnd(Layout.java:1409) 06-12 02:50:42.256 30175 30175 E ErrorPageActivity: at com.imdb.livingroom.firetv.util.TextViewExtensionsKt.visibleText(TextViewExtensions.kt:13)
问题代码
Kotlin扩展函数实现
fun TextView.visibleText(): String { val end = layout.getLineEnd(4) return layout.text.toString().substring(0,end); }
布局XML配置
<TextView android:id="@+id/user_review_description" style="@style/text_body_two" android:layout_width="@dimen/review_description_width" android:layout_height="wrap_content" android:layout_marginTop="@dimen/micro_margin" android:ellipsize="end" android:maxLines="5" android:layout_marginStart="@dimen/medium_margin" android:importantForAutofill= "noExcludeDescendants" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/user_nickname" />
运行效果

根因分析
- 调用时机错误:方法调用时TextView尚未完成布局测量与绘制流程,内部持有的
Layout对象未完成最终行数计算,即使XML配置了maxLines=5,当前Layout实例实际统计的行数小于5,直接传入索引4(行索引从0开始,对应第5行)访问行信息就会触发数组越界。 - 系统版本兼容问题:部分Android版本下,配置了
ellipsize属性的TextView在文本测量阶段会生成临时中间态Layout对象,该对象的行数统计和最终渲染行数不一致,也会触发越界异常。 - 列表复用场景问题:如果TextView位于RecyclerView等可复用列表控件中,复用时绑定的Layout可能是上一个条目遗留的旧实例,行信息和当前文本不匹配。
修复方案
- 扩展函数增加合法性校验,禁止硬编码行索引,调用行信息API前先校验Layout状态和实际行数,修正后代码如下:
fun TextView.visibleText(): String { val currentLayout = layout ?: return text.toString() val actualLineCount = currentLayout.lineCount val endIndex = if (actualLineCount >= 5) { currentLayout.getLineEnd(4) } else { currentLayout.text.length } return currentLayout.text.toString().substring(0, endIndex) } - 调整调用时机,不要在
onCreate、onBindViewHolder等布局未完成的生命周期阶段直接调用该方法,等待TextView布局完成后再执行取值逻辑:textView.doOnLayout { val visibleContent = it.visibleText() // 执行后续业务逻辑 } - 列表场景下必须保留行数校验逻辑,不能依赖XML配置的maxLines值直接写死行索引,避免复用导致的旧Layout数据不匹配问题。
内容的提问来源于stack exchange,提问作者Xiaoyu Jiang
相关产品推荐
相关产品推荐

