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

Kotlin协程在HartaActivity更新UI引发DiagnosticCoroutineContextException求助

问题:Kotlin协程在HartaActivity中触发RuntimeException

错误栈信息

java.lang.RuntimeException: Can't create handler inside thread Thread[DefaultDispatcher-worker-5,5,main] that has not called Looper.prepare()
                                                                                                        at android.os.Handler.<init>(Handler.java:207)
                                                                                                        at android.os.Handler.<init>(Handler.java:119)
                                                                                                        at android.view.textservice.SpellCheckerSession$1.<init>(SpellCheckerSession.java:107)
                                                                                                        at android.view.textservice.SpellCheckerSession.<init>(SpellCheckerSession.java:107)
                                                                                                        at android.view.textservice.TextServicesManager.newSpellCheckerSession(TextServicesManager.java:205)
                                                                                                        at android.widget.SpellChecker.resetSession(SpellChecker.java:129)
                                                                                                        at android.widget.SpellChecker.setLocale(SpellChecker.java:150)
                                                                                                        at android.widget.SpellChecker.spellCheck(SpellChecker.java:225)
                                                                                                        at android.widget.Editor.updateSpellCheckSpans(Editor.java:806)
                                                                                                        at android.widget.Editor.sendOnTextChanged(Editor.java:1377)
                                                                                                        at android.widget.TextView.sendOnTextChanged(TextView.java:10539)
                                                                                                        at android.widget.TextView.setText(TextView.java:6272)
                                                                                                        at android.widget.TextView.setText(TextView.java:6097)
                                                                                                        at android.widget.EditText.setText(EditText.java:122)
                                                                                                        at android.widget.TextView.setText(TextView.java:6049)
                                                                                                        at com.ch.al_mirats.presentation.kalkulator.harta.HartaActivity$displayWarisData$1.invokeSuspend(HartaActivity.kt:134)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
                                                                                                        at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
                                                                                                        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
                                                                                                        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@66c20ba, Dispatchers.IO]

相关代码

private fun displayWarisData() {
        GlobalScope.launch(Dispatchers.IO) {
            val loadedWarisData = warisDataDao.getAllWarisData()

            var harta = ""
            var hutang = ""
            var wasiat = ""
            var biayaPerawatanJenazah = ""


            for (warisData in loadedWarisData) {
                harta = warisData.harta.toString()
                hutang = warisData.hutang.toString()
                wasiat = warisData.wasiat.toString()
                biayaPerawatanJenazah = warisData.biayaPerawatanJenazah.toString()
            }
            val hartaEditable: Editable = Editable.Factory.getInstance().newEditable(if(harta == "0") "" else harta)
            val hutangEditable: Editable = Editable.Factory.getInstance().newEditable(if(hutang == "0") "" else hutang)
            val wasiatEditable: Editable = Editable.Factory.getInstance().newEditable(if(wasiat == "0") "" else wasiat)
            val biayaPerawatanJenazahEditable: Editable = Editable.Factory.getInstance().newEditable(if(biayaPerawatanJenazah == "0") "" else biayaPerawatanJenazah)

            binding.inputHarta.text = hartaEditable
            binding.inputHutang.text = hutangEditable
            binding.inputWasiat.text = wasiatEditable
            binding.inputBiayaPerawatanJenazah.text = biayaPerawatanJenazahEditable

        }
    }

原因分析

错误核心是在IO线程中执行UI操作:

  • Android要求所有UI组件的更新必须在主线程完成,你直接在Dispatchers.IO协程中调用EditText.setText(),违反了这个规则。
  • 具体触发点:EditText的setText()会触发系统拼写检查逻辑,而拼写检查需要创建Handler,但IO线程没有初始化Looper(仅主线程默认携带Looper),因此抛出Can't create handler inside thread that has not called Looper.prepare()异常。

解决方案

将UI更新逻辑切换到主线程执行,修改后的代码如下:

private fun displayWarisData() {
        // 用lifecycleScope替代GlobalScope,避免内存泄漏
        lifecycleScope.launch(Dispatchers.IO) {
            val loadedWarisData = warisDataDao.getAllWarisData()

            var harta = ""
            var hutang = ""
            var wasiat = ""
            var biayaPerawatanJenazah = ""

            // 注意:当前循环仅保留最后一条数据的值,若需其他逻辑请自行调整
            for (warisData in loadedWarisData) {
                harta = warisData.harta.toString()
                hutang = warisData.hutang.toString()
                wasiat = warisData.wasiat.toString()
                biayaPerawatanJenazah = warisData.biayaPerawatanJenazah.toString()
            }
            // 提前处理字符串,避免在主线程做冗余操作
            val hartaStr = if(harta == "0") "" else harta
            val hutangStr = if(hutang == "0") "" else hutang
            val wasiatStr = if(wasiat == "0") "" else wasiat
            val biayaStr = if(biayaPerawatanJenazah == "0") "" else biayaPerawatanJenazah

            // 切换到主线程更新UI
            withContext(Dispatchers.Main) {
                binding.inputHarta.setText(hartaStr)
                binding.inputHutang.setText(hutangStr)
                binding.inputWasiat.setText(wasiatStr)
                binding.inputBiayaPerawatanJenazah.setText(biayaStr)
            }
        }
    }

额外优化建议

  • 替换GlobalScope:使用lifecycleScope(Activity/Fragment专属)或viewModelScope(ViewModel专属)替代GlobalScope,它们会自动跟随组件生命周期取消协程,彻底避免内存泄漏。
  • 简化Editable创建:无需手动创建Editable,EditText.setText(CharSequence)会自动完成转换,直接传入字符串即可。
  • 循环逻辑优化:当前循环会覆盖变量值,最终仅保留最后一条warisData的数据。如果你的需求是获取第一条数据或合并所有数据,请调整循环逻辑。

内容的提问来源于stack exchange,提问作者ryhanhxx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:59:52