Android 15/16:从浏览器返回(深链接)时,Fragment中会出现日夜主题混用的情况——新创建的Fragment使用系统的暗色主题,旧的Fragment仍保持亮色主题

移动开发 2026-07-12

我有一个使用 AppCompat DayNight 的Android应用(Theme.MaterialComponents.DayNight.NoActionBar)。

目标

  • 首次启动:应用应跟随操作系统主题(可选)。
  • 在用户手动选择 LightDark 之后,应用必须始终使用保存的主题,即使通过deeplink从外部应用(浏览器)返回时也保持该主题。

当前实现

在Activity启动时,我在 super.onCreate() 之前应用主题:

override fun onCreate(savedInstanceState: Bundle?) {
    initTheme()
    super.onCreate(savedInstanceState)
    setContentView(...)
}

private fun initTheme() {
    when (Configs.getCurrentTheme(this)) {
        "light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
        "dark"  -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    }
}

主题偏好保存在SharedPreferences中:

object Configs {
    private const val selectedTheme = "selectedTheme"

    fun saveSelectedTheme(context: Context, value: String) {
        PreferencesManager.getInstance(context).save(selectedTheme, value)
    }

    fun getCurrentTheme(context: Context) =
        PreferencesManager.getInstance(context).read<String>(selectedTheme).let {
            it.ifEmpty {
                when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
                    Configuration.UI_MODE_NIGHT_YES -> "dark"
                    else -> "light"
                }
            }
        }
}

当用户手动切换主题时,我会重启Activity(这种方式从不崩溃):

Configs.saveSelectedTheme(
    this,
    if (Configs.getCurrentTheme(this) == "light") "dark" else "light"
)
finish()
startActivity(Intent(this, MainActivity::class.java))

问题(仅Android 15/16)

在Android 14及以下一切正常。

Android 15/16(在Samsung / Honor / NothingPhone上测试):

  1. 系统主题为 Dark
  2. 应用保存的主题是 LightMODE_NIGHT_NO
  3. 在应用内,我打开一个浏览器(ACTION_VIEW URL)
  4. 通过 deeplink 返回应用

返回后:

  • 现有/较旧的Fragment(在浏览器前创建)仍显示为 Light
  • 任何在返回后创建的新Fragment将变为 Dark(系统主题)
  • 结果是在各Fragment之间出现混合主题的UI

所以看起来从浏览器返回时,Activity/Resources暂时仿佛在应用系统UI模式(暗色),尽管应用夜间模式已固定为明亮。

约束 / 细节

  • 我没有 android:configChanges 用于 uiMode 等。
  • 父主题是 Theme.MaterialComponents.DayNight.NoActionBar

因此我需要一个解决方案:

  • 在Android 15/16返回自浏览器/ deeplink时防止出现混合主题
  • 最好不要依赖 recreate()

我尝试过什么

  • super.onCreate 之前提前调用 AppCompatDelegate.setDefaultNightMode(...)
  • 通过 delegate.applyDayNight()onResume() / onNewIntent() 重新应用Day/Night
  • 使用 delegate.localNightMode
  • 不匹配时重启Activity(有时有效但不稳定;另外尝试重新创建会导致我的导航栈崩溃)

问题

在返回自外部应用(浏览器)通过deeplink后,确保应用保持在已保存的Day/Night模式的正确且可靠的做法是什么,特别是在Android 15/16上,避免出现混合主题的Fragment?

如果存在已知的Android 15/16行为变更或推荐的变通办法(例如使用 uiMode 处理、上下文包装、清单配置,或特定的AppCompat API用法),请分享。

解决方案

@Saman,我对这个问题很感兴趣。
请在加载设置前尝试添加0.01或 0.1秒的延迟?
我认为这可能是一种解决方案,请告诉我是否有效。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章