为什么要单独把这个异常拿出来说,因为这个异常出现的比较诡异,先看抛出的异常,如下图:
图1上图是在华为兼容测试里面生成的,出现这个问题的原因有三种:
1、可能是下标计算有误,导致start和end负值;
2、手机开启无障碍模式的TalkBack功能,如果start==end也会;
3、实现ClickableSpan时为了解决内存泄漏问题,按照网上的方法实现了NoCopySpan。部分机型可能不支持NoCopySpan的实现,导致异常报错,去除后恢复正常。
本人出现的问题是第二种,图中可以看出有无障碍模式的api(即 Accessibility)。正常测试的话是无法发现这个问题的。当上线通过渠道遍历测试则会爆出这个异常。先查看源码找到SpannableStringBuilder中的checkRange方法,如图2:
图2按理说怎么可能start和end都小于0呢,而且当start==end 也报 setSpan(-1...-1)starts before0,崩溃产生在辅助功能开启后,关键错误代码 是 android.view.accessibility.AccessibilityNodeInfo.setText(AccessibilityNodeInfo.java:2645)
查看源码,如图3:
图3private IdentityHashMap<Object,Integer> mIndexOfSpan;
public intget SpanStart(Objectwhat){
if(mIndexOfSpan==null) return-1;
Integeri=mIndexOfSpan.get(what);
returni==null?-1:resolveGap(mSpanStarts[i]);
}
当mIndexOfSpan==null时,返回-1,所以
int spanToReplaceStart =spannable.getSpanStart(span);
int spanToReplaceEnd =spannable.getSpanEnd(span);
都返回-1;
修改方法:
根据源码来看 mIndexOfSpan 不为空即可解决
SpannableString s =new SpannableString(destStr);
s.setSpan(clickSpan,start,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textview.setText(s);
替换成
SpannableStringBuilderspan Str = SpannableStringBuilder.valueOf(destStr);
spanStr.setSpan(clickSpan,start,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textview.setText(spanStr);
测试结果:
通过
网友评论