為什么要單獨(dú)把這個(gè)異常拿出來(lái)說(shuō),因?yàn)檫@個(gè)異常出現(xiàn)的比較詭異,先看拋出的異常,如下圖:
上圖是在華為兼容測(cè)試?yán)锩嫔傻模霈F(xiàn)這個(gè)問(wèn)題的原因有三種:
1、可能是下標(biāo)計(jì)算有誤,導(dǎo)致start和end負(fù)值;
2、手機(jī)開(kāi)啟無(wú)障礙模式的TalkBack功能,如果start==end也會(huì);
3、實(shí)現(xiàn)ClickableSpan時(shí)為了解決內(nèi)存泄漏問(wèn)題,按照網(wǎng)上的方法實(shí)現(xiàn)了NoCopySpan。部分機(jī)型可能不支持NoCopySpan的實(shí)現(xiàn),導(dǎo)致異常報(bào)錯(cuò),去除后恢復(fù)正常。
本人出現(xiàn)的問(wèn)題是第二種,圖中可以看出有無(wú)障礙模式的api(即?Accessibility)。正常測(cè)試的話是無(wú)法發(fā)現(xiàn)這個(gè)問(wèn)題的。當(dāng)上線通過(guò)渠道遍歷測(cè)試則會(huì)爆出這個(gè)異常。先查看源碼找到SpannableStringBuilder中的checkRange方法,如圖2:
按理說(shuō)怎么可能start和end都小于0呢,而且當(dāng)start==end 也報(bào) setSpan(-1...-1)starts before0,崩潰產(chǎn)生在輔助功能開(kāi)啟后,關(guān)鍵錯(cuò)誤代碼 是 android.view.accessibility.AccessibilityNodeInfo.setText(AccessibilityNodeInfo.java:2645)
查看源碼,如圖3:
private IdentityHashMap<Object,Integer>? mIndexOfSpan;
public intget SpanStart(Objectwhat){
if(mIndexOfSpan==null) return-1;
Integeri=mIndexOfSpan.get(what);
returni==null?-1:resolveGap(mSpanStarts[i]);
}
當(dāng)mIndexOfSpan==null時(shí),返回-1,所以
int? ?spanToReplaceStart? =spannable.getSpanStart(span);
int? ? spanToReplaceEnd? =spannable.getSpanEnd(span);
都返回-1;
修改方法:
根據(jù)源碼來(lái)看 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);
測(cè)試結(jié)果:
通過(guò)