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
相关产品推荐
相关产品推荐

