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

从BottomSheetFragment切换明暗主题导致应用崩溃的解决求助

问题解决:切换主题时崩溃“You cannot start a load for a destroyed activity”

崩溃原因

直接调用AppCompatDelegate.setDefaultNightMode会触发应用全局主题重建,包括当前Activity和Fragment的重建。如果此时BottomSheetFragment依附的Activity已经处于销毁/即将销毁状态,或者重建过程中上下文失效,就会抛出这个异常。

可行实现方案

方案1:先检查Activity状态再执行切换

在切换主题前,先确认BottomSheetFragment的宿主Activity是否处于有效状态,避免在Activity销毁时执行操作:

binding.themesettingScLightdark.setOnCheckedChangeListener { _, isChecked ->
    val hostActivity = requireActivity()
    // 检查Activity是否未被销毁且未在结束流程中
    if (!hostActivity.isDestroyed && !hostActivity.isFinishing) {
        val nightMode = if (isChecked) {
            AppCompatDelegate.MODE_NIGHT_YES
        } else {
            AppCompatDelegate.MODE_NIGHT_NO
        }
        AppCompatDelegate.setDefaultNightMode(nightMode)
    }
}

方案2:通过宿主Activity处理主题切换(更可靠)

让BottomSheetFragment通过回调通知宿主Activity执行主题切换,避免Fragment直接操作全局主题导致的上下文问题:

  1. 在BottomSheetFragment中定义回调接口:
class ThemeBottomSheetFragment : BottomSheetDialogFragment() {
    private var themeChangeListener: ThemeChangeListener? = null

    interface ThemeChangeListener {
        fun onThemeChanged(isDarkMode: Boolean)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        // 确保宿主Activity实现了回调接口
        if (context is ThemeChangeListener) {
            themeChangeListener = context
        } else {
            throw RuntimeException("$context must implement ThemeChangeListener")
        }
    }

    override fun onDetach() {
        super.onDetach()
        themeChangeListener = null // 避免内存泄漏
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding = ThemesettingScBinding.inflate(inflater, container, false)
        binding.themesettingScLightdark.setOnCheckedChangeListener { _, isChecked ->
            themeChangeListener?.onThemeChanged(isChecked)
            dismiss() // 切换后关闭BottomSheet
        }
        // 初始化开关状态为当前主题
        val currentMode = AppCompatDelegate.getDefaultNightMode()
        binding.themesettingScLightdark.isChecked = currentMode == AppCompatDelegate.MODE_NIGHT_YES
        return binding.root
    }
}
  1. 在宿主Activity中实现回调接口:
class MainActivity : AppCompatActivity(), ThemeBottomSheetFragment.ThemeChangeListener {
    override fun onThemeChanged(isDarkMode: Boolean) {
        // 检查Activity状态
        if (!isDestroyed && !isFinishing) {
            val nightMode = if (isDarkMode) {
                AppCompatDelegate.MODE_NIGHT_YES
            } else {
                AppCompatDelegate.MODE_NIGHT_NO
            }
            AppCompatDelegate.setDefaultNightMode(nightMode)
        }
    }
}

额外注意点

  • 保存开关状态:主题切换会触发Activity/Fragment重建,可通过ViewModel或者SavedInstanceState保存开关的选中状态,重建后恢复。
  • 切换后关闭BottomSheet:避免主题重建时BottomSheet重复出现,可在触发切换后调用dismiss()关闭弹窗。

内容的提问来源于stack exchange,提问作者Suryansh Singh Rajput

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:52:15