Android主题切换如何避免屏幕闪烁?单Activity架构无需重启方案
解决方案
1. 禁用系统默认Activity重建行为
首先在AndroidManifest.xml中给你的单主Activity添加configChanges配置,拦截主题变化导致的系统重建,避免导航栈丢失:
<activity android:name=".MainActivity" android:configChanges="uiMode|screenLayout|screenSize|smallestScreenSize|orientation" android:exported="true"> <!-- 原有intent-filter等配置保持不变 --> </activity>
2. 添加过渡动画消除闪烁
直接全局重绘View会因为前后色值差异大出现闪烁,可以通过临时快照过渡层实现平滑切换:
调整ThemeManager实现
将Flow收集逻辑和Activity生命周期绑定,避免内存泄漏,同时过滤重复主题触发:
class ThemeManager( private val themeDataStore: ThemeDataStore, private val coroutineScope: CoroutineScope ) { // 加distinctUntilChanged避免相同主题重复触发切换 val currentThemeFlow = themeDataStore.themeFlow.distinctUntilChanged() fun setCurrentTheme(newTheme: Int) { coroutineScope.launch { themeDataStore.updateTheme(newTheme) } } } // 在主Activity中初始化 val themeManager = ThemeManager(themeDataStore, lifecycleScope)
主Activity中添加切换过渡逻辑
在主ActivityonCreate方法中添加主题变化监听,通过快照过渡消除闪烁:
lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { themeManager.currentThemeFlow.collect { newTheme -> val decorView = window.decorView // 1. 拍摄当前界面快照作为过渡层 val snapshot = Bitmap.createBitmap(decorView.width, decorView.height, Bitmap.Config.ARGB_8888) val canvas = Canvas(snapshot) decorView.draw(canvas) val snapshotView = ImageView(this@MainActivity) snapshotView.setImageBitmap(snapshot) decorView.addView(snapshotView) // 2. 执行主题切换 AppCompatDelegate.setDefaultNightMode(newTheme) // 3. 界面重绘完成后淡出过渡层 snapshotView.animate() .alpha(0f) .setDuration(150) // 过渡时长可自行调整 .withEndAction { decorView.removeView(snapshotView) snapshot.recycle() } .start() } } }
3. 冷启动适配
在主Activity的super.onCreate()调用前,先读取存储的主题值调用AppCompatDelegate.setDefaultNightMode()设置,避免冷启动阶段出现闪屏。
内容的提问来源于stack exchange,提问作者Arpit Shukla
相关产品推荐
相关产品推荐

