You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中使用SpannableStringBuilder与TextView时偶发setSpan越界崩溃问题求助

Android中使用SpannableStringBuilder与TextView时偶发setSpan越界崩溃问题求助

我在Android开发中使用SpannableStringBuilder和TextView时遇到了偶发的崩溃问题,错误提示为java.lang.IndexOutOfBoundsException: setSpan (0 ... -1) has end before start。这个崩溃不是每次都会出现,但偶尔触发,实在让人头疼。

具体场景是:在Fragment中,我通过LiveData接收Service里更新的SpannableStringBuilder对象,用来更新界面上的TextView。下面是相关的Java代码、Logcat日志以及变量输出,希望能得到大佬们的帮助找到修复方法。我已经在Google Issue Tracker和Stack Overflow上查找过,没找到完全匹配的错误信息,类似的问题也解决不了我的情况。


相关代码

Fragment代码

public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {

    super.onViewCreated(view, savedInstanceState);

    ...

    textViewLog = (TextView)view.findViewById(R.id.textview_log);
    scrollview = ((NestedScrollView)  view.findViewById(R.id.scrollview));

    // Create the observer which updates the UI.
    final Observer<SpannableStringBuilder> ETAObserver = new Observer<SpannableStringBuilder>() {
        @Override
        public void onChanged(@Nullable final SpannableStringBuilder spannableLog) {
            // Update the UI, in this case, a TextView.
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    String textViewLogStringBeforeUpdate = null;
                    if (BuildConfig.IS_TESTING.get()) {
                        // For Debug purposes: to try to understand this rare exception
                        // java.lang.IndexOutOfBoundsException: setSpan (0 ... -1) has end before start
                        textViewLogStringBeforeUpdate = textViewLog.getText().toString();
                    }
                    try {
                        textViewLog.setText(spannableLog);
                    } catch (IndexOutOfBoundsException e) {
                        String msg = e.getMessage();
                        if (msg != null && msg.startsWith("setSpan")) {
                            e.printStackTrace();
                            Log.e("ETATest", "Crash with message: " + msg);
                            Log.v("ETATest", "textViewLog Before: " + textViewLogStringBeforeUpdate);
                            Log.v("ETATest", "spannableLog: " + spannableLog);
                            Log.v("ETATest", "textViewLog After: " + textViewLog.getText());
                        } else {
                            throw e;
                        }
                    }
                    // Stuff that updates the UI
                    scrollview.post(new Runnable() {
                        @Override
                        public void run() {
                            scrollview.fullScroll(ScrollView.FOCUS_DOWN);
                        }
                    });
                }
            });
        }
    };

    // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
    AddThumbsLogLiveData.get().observe(getViewLifecycleOwner(), ETAObserver);
}

LogLiveData代码

public class AddThumbsLogLiveData extends LiveData<SpannableStringBuilder> {

    private static AddThumbsLogLiveData sInstance;
    private final static SpannableStringBuilder log = new SpannableStringBuilder("");

    @MainThread
    public static AddThumbsLogLiveData get() {
        if (sInstance == null) {
            sInstance = new AddThumbsLogLiveData();
        }
        return sInstance;
    }

    private AddThumbsLogLiveData() {
    }

    public void appendLog(String text) {
        if (enableLog) Log.i(TAG, text);
        log.append(text);
        postValue(log);
    }

    public void appendLog(Spanned text) {
        if (enableLog) Log.i(TAG, text.toString());
        log.append(text);
        postValue(log);
    }

    public void clear() {
        log.clear();
    }
}

崩溃日志及变量输出

03-10 10:22:36.446 16047 16413 I ETALog  : Processing /storage/emulated/0/DCIM/test_standard_addThumbsSettingsDefaultTwoRuns
03-10 10:22:36.455 16047 16413 I ETALog  : Checking permissions…
03-10 10:22:36.458 16047 16413 I ETALog  :  Successful
03-10 10:22:36.460 16047 16047 W System.err: java.lang.IndexOutOfBoundsException: setSpan (0 ... -1) has end before start
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannableStringInternal.checkRange(SpannableStringInternal.java:485)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:199)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannableStringInternal.copySpansFromSpanned(SpannableStringInternal.java:87)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannableStringInternal.<init>(SpannableStringInternal.java:48)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannedString.<init>(SpannedString.java:35)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.SpannedString.<init>(SpannedString.java:44)
03-10 10:22:36.476 16047 16047 W System.err:    at android.text.TextUtils.stringOrSpannedString(TextUtils.java:532)
03-10 10:22:36.476 16047 16047 W System.err:    at android.widget.TextView.setText(TextView.java:6318)
03-10 10:22:36.476 16047 16047 W System.err:    at android.widget.TextView.setText(TextView.java:6227)
03-10 10:22:36.476 16047 16047 W System.err:    at android.widget.TextView.setText(TextView.java:6179)
03-10 10:22:36.476 16047 16047 W System.err:    at com.exifthumbnailadder.app.AddThumbsFragment$4$1.run(AddThumbsFragment.java:162)
03-10 10:22:36.476 16047 16047 W System.err:    at android.app.Activity.runOnUiThread(Activity.java:7133)
03-10 10:22:36.476 16047 16047 W System.err:    at com.exifthumbnailadder.app.AddThumbsFragment$4.onChanged(AddThumbsFragment.java:152)
03-10 10:22:36.476 16047 16047 W System.err:    at com.exifthumbnailadder.app.AddThumbsFragment$4.onChanged(AddThumbsFragment.java:148)
03-10 10:22:36.476 16047 16047 W System.err:    at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
03-10 10:22:36.476 16047 16047 W System.err:    at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
03-10 10:22:36.476 16047 16047 W System.err:    at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
03-10 10:22:36.476 16047 16047 W System.err:    at androidx.lifecycle.LiveData$1.run(LiveData.java:93)
03-10 10:22:36.476 16047 16047 W System.err:    at android.os.Handler.handleCallback(Handler.java:938)
03-10 10:22:36.476 16047 16047 W System.err:    at android.os.Handler.dispatchMessage(Handler.java:99)
03-10 10:22:36.476 16047 16047 W System.err:    at android.os.Looper.loopOnce(Looper.java:201)
03-10 10:22:36.476 16047 16047 W System.err:    at android.os.Looper.loop(Looper.java:288)
03-10 10:22:36.477 16047 16047 W System.err:    at android.app.ActivityThread.main(ActivityThread.java:7839)
03-10 10:22:36.477 16047 16047 W System.err:    at java.lang.reflect.Method.invoke(Native Method)
03-10 10:22:36.477 16047 16047 W System.err:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
03-10 10:22:36.477 16047 16047 W System.err:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
03-10 10:22:36.477 16047 16047 E ETATest : Crash with message: setSpan (0 ... -1) has end before start
03-10 10:22:36.477 16047 16047 V ETATest : textViewLog Before: Starting…
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking working directory permissions… Successful
03-10 10:22:36.477 16047 16047 V ETATest :
03-10 10:22:36.477 16047 16047 V ETATest : Processing /storage/emulated/0/DCIM/test_standard_addThumbsSettingsDefaultTwoRuns
03-10 10:22:36.477 16047 16047 V ETATest : spannableLog: Starting…
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking working directory permissions… Successful
03-10 10:22:36.477 16047 16047 V ETATest :
03-10 10:22:36.477 16047 16047 V ETATest : Processing /storage/emulated/0/DCIM/test_standard_addThumbsSettingsDefaultTwoRuns
03-10 10:22:36.477 16047 16047 V ETATest : Checking permissions… Successful
03-10 10:22:36.477 16047 16047 V ETATest : textViewLog After: Starting…
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking permission to access storage… Successful
03-10 10:22:36.477 16047 16047 V ETATest : Checking working directory permissions… Successful
03-10 10:22:36.477 16047 16047 V ETATest :
03-10 10:22:36.477 16047 16047 V ETATest : Processing /storage/emulated/0/DCIM/test_standard_addThumbsSettingsDefaultTwoRuns

备注:内容来源于stack exchange,提问作者usilo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 09:24:12