Android 15/16:从浏览器返回(深链接)时,Fragment中会出现日夜主题混用的情况——新创建的Fragment使用系统的暗色主题,旧的Fragment仍保持亮色主题
我有一个使用 AppCompat DayNight 的Android应用(Theme.MaterialComponents.DayNight.NoActionBar)。
目标
- 首次启动:应用应跟随操作系统主题(可选)。
- 在用户手动选择 Light 或 Dark 之后,应用必须始终使用保存的主题,即使通过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上测试):
- 系统主题为 Dark
- 应用保存的主题是 Light(
MODE_NIGHT_NO) - 在应用内,我打开一个浏览器(
ACTION_VIEWURL) - 通过 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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。