欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

setSpan 报错 IndexOutOfBounds

程序员文章站 2022-03-24 22:04:58
近期在项目开发中发现如下报错之前一直以为是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...

近期在项目开发中发现如下报错
setSpan 报错 IndexOutOfBounds
之前一直以为是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的用户有一点影响。 目前还没有更好的解决方法。

本文地址:https://blog.csdn.net/Dullyoung/article/details/108978215