概述
近期在项目开发中发现如下报错
之前一直以为是SpanString的问题 一直用try - catch来处理。
@Override
public void setSpan(Object what, int start, int end, int flags) {
if (start == -1 || end == -1 || end > mCharSequence.length()) {
return;
}
try {
super.setSpan(what, start, end, flags);
} catch (Exception e) {
e.printStackTrace();
}
}
但在实际项目中并不凑效,bugly后台一直在报错,跟进Accessiblity源码,其中有setSpan的调用,查询相关资料发现是clickSpan和无障碍的TalkBack不能同时使用,这两者有冲突,用了clickSpan会让TalkBack读取文字的时候读不到下标 进而导致IndexOutOfBounds的报错。
解决方法是判断是否开启屏幕阅读器 TalkBack。
public final static String SCREEN_READER_INTENT_ACTION = "android.accessibilityservice.AccessibilityService";
public final static String SCREEN_READER_INTENT_CATEGORY = "android.accessibilityservice.category.FEEDBACK_SPOKEN";
public static boolean isScreenReaderActive(Context context) {
// 通过Intent方式判断是否存在以语音播报方式提供服务的Service,还需要判断开启状态
Intent screenReaderIntent = new Intent(SCREEN_READER_INTENT_ACTION);
screenReaderIntent.addCategory(SCREEN_READER_INTENT_CATEGORY);
List<ResolveInfo> screenReaders = context.getPackageManager().queryIntentServices(screenReaderIntent, 0);
// 如果没有,返回false
if (screenReaders == null || screenReaders.size() <= 0) {
return false;
}
boolean hasActiveScreenReader = false;
if (Build.VERSION.SDK_INT <= 15) {
ContentResolver cr = context.getContentResolver();
Cursor cursor = null;
int status = 0;
for (ResolveInfo screenReader : screenReaders) {
cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
+ ".providers.StatusProvider"), null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
status = cursor.getInt(0);
cursor.close();
// 状态1为开启状态,直接返回true即可
if (status == 1) {
return true;
}
}
}
} else if (Build.VERSION.SDK_INT >= 26) {
// 高版本可以直接判断服务是否处于开启状态
for (ResolveInfo screenReader : screenReaders) {
hasActiveScreenReader |= isAccessibilitySettingsOn(context, screenReader.serviceInfo.packageName + "/" + screenReader.serviceInfo.name);
}
} else {
// 判断正在运行的Service里有没有上述存在的Service
List<String> runningServices = new ArrayList<String>();
android.app.ActivityManager manager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (android.app.ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
runningServices.add(service.service.getPackageName());
}
for (ResolveInfo screenReader : screenReaders) {
if (runningServices.contains(screenReader.serviceInfo.packageName)) {
hasActiveScreenReader = true;
break;
}
}
}
return hasActiveScreenReader;
}
public static boolean isAccessibilitySettingsOn(Context context, String service) {
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
String settingValue = Settings.Secure.getString(
context.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
return false;
}
每次使用clickSpan之前 判断isScreenReaderActive(),如果开启了TB,就不设置clickSpan。不会影响正常使用,但是对开启了TB的用户有一点影响。 目前还没有更好的解决方法。
最后
以上就是感动大象为你收集整理的setSpan 报错 IndexOutOfBounds的全部内容,希望文章能够帮你解决setSpan 报错 IndexOutOfBounds所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复