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

Android Kotlin协程运行异常,启动Activity时部分设备出现崩溃闪退问题

代码问题分析
  • 永久挂起的流收集未终止:DataStore的data是冷流,调用collect后会永久挂起监听后续数据变化,不会主动结束。就算拿到了首次启动的判断值,后续DataStore任意数据更新都会再次触发回调,此时页面可能已经跳转、Activity已销毁,执行UI操作就会触发崩溃。
  • 嵌套流收集加重泄漏问题:在首个collect的else分支中又启动了第二个dataStore.data.collect,同一时间存在两个永久运行的收集器,资源泄漏风险更高,多次触发跳转逻辑也会导致状态异常。
  • 协程未绑定Activity生命周期:直接使用CoroutineScope(Dispatchers.Main)创建无生命周期绑定的作用域,Activity销毁时协程不会自动取消,后续切主线程执行UI操作时会因为Context/View为空抛出异常。
  • 冗余线程切换:外层协程已经运行在主线程,内部多次手动调用withContext(Dispatchers.Main)属于冗余操作,且DataStore的读写内部已经实现线程调度,不需要手动切IO线程执行。
修复方案

优先解决流永久监听和协程生命周期问题,调整后的代码如下:

// 使用lifecycleScope绑定Activity生命周期,页面销毁自动取消协程
lifecycleScope.launch {
    // 仅获取一次当前是否首次启动的配置,不持续监听
    val notFirstLaunch = dataStore.data
        .map { preferences -> preferences[DataStoreManager.NOT_FIRST_LUNCH] ?: false }
        .first()
    
    if (!notFirstLaunch) {
        editBoolean(DataStoreManager.NOT_FIRST_LUNCH, true)
        // lifecycleScope默认运行在主线程,无需额外切换
        activityFullscreenCompat()
        setContentView(R.layout.activity_lunch)
        prepareIntro()
        lunch_btn_skip.setOnClickListener {
            gotoMain()
        }
    } else {
        // 仅获取一次暗色模式配置
        val isNight = dataStore.data
            .map { preferences -> preferences[DataStoreManager.IS_NIGHT] ?: false }
            .first()
        AppCompatDelegate.setDefaultNightMode(
            if (isNight) AppCompatDelegate.MODE_NIGHT_YES 
            else AppCompatDelegate.MODE_NIGHT_NO
        )
        gotoMain()
    }
}
补充注意事项
  • 如果确实需要监听DataStore的配置变化,建议将收集逻辑放在launchWhenStarted/launchWhenResumed中,仅在Activity处于前台时执行,避免后台操作引发异常
  • 执行gotoMain跳转后建议调用finish()销毁当前启动页,避免返回键回退到该页面
  • 确保editBoolean方法的DataStore写入操作采用单次写入逻辑,不要触发不必要的数据流更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:15:07