chinalwb / Android-Rich-text-Editor

Android Rich Text Editor With customized spans - 富文本编辑器 - Don't miss this one :)
Apache License 2.0
841 stars 169 forks source link

fix ARE_ABS_Dynamic_Style IndexOutOfBoundException #130

Open Savion1162336040 opened 3 years ago

Savion1162336040 commented 3 years ago

修复ARE_ABS_Dynamic_Style闪退 复现场景 【1】、输入 :123456789 【2】、修改 :"89" 的颜色为红色 【3】、修改 :"67" 的颜色为绿色 【4】、闪退 :报错如下

java.lang.IndexOutOfBoundsException: setSpan (7 ... 5) has end before start
        at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1314)
        at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:682)
        at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:674)
        at com.chinalwb.are.styles.ARE_ABS_Dynamic_Style.applyNewStyle(ARE_ABS_Dynamic_Style.java:87)
        at com.chinalwb.are.styles.ARE_FontColor$1.onPickColor(ARE_FontColor.java:36)
        at com.chinalwb.are.colorpicker.ColorPickerView$1.onClick(ColorPickerView.java:108)

以下是ARE_ABS_Dynamic_Style源码

        int detectStart = start;
        if (start > 0) {
            detectStart = start - 1;
        }
        int detectEnd = end;
        if (end < editable.length()) {
            detectEnd = end + 1;
        }
        E[] existingSpans = editable.getSpans(detectStart, detectEnd, clazzE);
        if (existingSpans != null && existingSpans.length > 0) {
            for (E span : existingSpans) {
                int spanStart = editable.getSpanStart(span);

                if (spanStart < startSpanStart) {
                    startSpanStart = spanStart;
                    startSpan = span;
                }

                if (spanStart >= endSpanStart) {
                    endSpanStart = spanStart;
                    endSpan = span;
                    int thisSpanEnd = editable.getSpanEnd(span);
                    if (thisSpanEnd > endSpanEnd) {
                        endSpanEnd = thisSpanEnd;
                    }
                }
            } // End for
            ......
            int startSpanFeature = startSpan.getDynamicFeature();
            int endSpanFeature = endSpan.getDynamicFeature();
            if (startSpanFeature == currentStyle && endSpanFeature == currentStyle) {
                editable.setSpan(newSpan(), startSpanStart, endSpanEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
            } else if (startSpanFeature == currentStyle) {
                editable.setSpan(newSpan(startSpanFeature), startSpanStart, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                editable.setSpan(newSpan(endSpanFeature), end, endSpanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            } else if (endSpanFeature == currentStyle) {
                editable.setSpan(newSpan(startSpanFeature), startSpanStart, start, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                editable.setSpan(newSpan(endSpanFeature), start, endSpanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            } else {
                editable.setSpan(newSpan(startSpanFeature), startSpanStart, start, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                if (endSpanEnd > end) {
                    editable.setSpan(newSpan(endSpanFeature), end, endSpanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
                }
                editable.setSpan(newSpan(), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
            }

通过审核代码后发现执行测试场景步骤【3】时,existingSpans会取到字符 "89" 的span,此时

start=5
startSpanStart=7
endSpanStart=7
endSpanEnd=9

执行到如下代码时由于startSpanStart<start,此时就抛出了异常

editable.setSpan(newSpan(startSpanFeature), startSpanStart, start, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
chinalwb commented 3 years ago

多谢 PR!

chinalwb commented 3 years ago

能把我这烂代码看到这个程度的也真是可以了!👍👍👍

Savion1162336040 commented 3 years ago

老哥谦虚了,这套方案也给我很大启发,已经很棒了