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

调用requireActivity().recreate()重启Activity时如何避免短暂黑屏?

更改Locale后调用recreate()出现黑屏的解决方案

黑屏的根本原因是recreate()执行时,系统销毁旧Activity、创建新Activity的过渡间隙,会默认显示当前Activity主题设置的windowBackground属性值,未自定义该属性时通常会显示系统默认的黑色背景,也就是你看到的0.3秒黑屏。以下是3种可行的实现方案,可根据你的项目情况选择:

方案1:自定义过渡窗口背景(成本最低,推荐优先尝试)

直接修改主题的windowBackground属性,让过渡间隙显示你需要的闪屏/进度条占位图,不需要修改业务逻辑:

  • 第一步:在res/drawable目录下创建占位图drawable,示例如下:
<!-- res/drawable/locale_switch_placeholder.xml -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 背景色可替换为你的产品主色 -->
    <item android:drawable="@color/white" />
    <!-- 中间显示进度条,也可替换为产品logo等自定义内容 -->
    <item android:gravity="center">
        <rotate android:fromDegrees="0" android:toDegrees="360">
            <shape android:shape="oval">
                <size android:width="32dp" android:height="32dp" />
                <stroke android:width="3dp" android:color="@color/your_primary_color" />
            </shape>
        </rotate>
    </item>
</layer-list>
  • 第二步:给目标Activity的主题添加windowBackground配置:
<style name="YourActivityTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- 其他原有主题配置 -->
    <item name="android:windowBackground">@drawable/locale_switch_placeholder</item>
    <!-- 可选:关闭默认Activity过渡动画,避免闪烁 -->
    <item name="android:windowAnimationStyle">@null</item>
</style>
  • 第三步:在Activity的onCreate方法中恢复正常窗口背景,避免占位图影响日常页面显示:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 恢复为普通页面的窗口背景,可根据你的业务需求设置
    window.setBackgroundDrawableResource(R.color.white)
    setContentView(R.layout.your_activity_layout)
    // 其他原有业务逻辑
}

方案2:手动刷新UI避免Activity重建(完全无黑屏,推荐性能要求高的场景)

不调用系统的recreate()方法,Locale更改后手动刷新当前页面所有文本资源,从根源上避免销毁重建的过渡过程:

  • 更改Locale配置后先更新应用全局资源配置:
fun updateAppLocale(newLocale: Locale) {
    val resources = requireContext().resources
    val config = resources.configuration
    config.setLocale(newLocale)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        config.setLocales(LocaleList(newLocale))
    }
    resources.updateConfiguration(config, resources.displayMetrics)
}
  • 手动更新当前页面所有View的文本内容:
fun refreshUIAfterLocaleChange() {
    // 所有文本资源重新从strings.xml取值赋值
    binding.titleTv.setText(R.string.page_title)
    binding.confirmBtn.setText(R.string.confirm)
    // 刷新列表、Fragment等组件
    contentAdapter.notifyDataSetChanged()
    childFragmentList.forEach { it.refreshLocaleText() }
}

如果你的项目使用了ViewModel+LiveData/Flow,可以将Locale状态作为全局可监听数据,所有文本通过监听Locale状态自动更新,不需要手动逐个赋值。

方案3:重建前添加全屏覆盖层(适合必须使用recreate()的场景)

如果你的业务逻辑依赖Activity重建,无法使用方案2,可以在触发重建前先显示一个全屏的覆盖层展示闪屏/进度条,重建完成后再隐藏:

  • 触发Locale切换时先显示全屏无动画Dialog:
fun switchLocale(newLocale: Locale) {
    // 创建全屏进度Dialog
    val progressDialog = Dialog(requireContext(), android.R.style.Theme_Black_NoTitleBar_Fullscreen)
    progressDialog.setContentView(R.layout.your_splash_progress_layout)
    progressDialog.setCancelable(false)
    progressDialog.window?.setDimAmount(0f)
    progressDialog.show()
    
    // 全局存储重建标记,可放在Application类或者静态变量中
    MyApp.isLocaleRebuilding = true
    // 存储Dialog实例,或者在重建后重新获取
    MyApp.tempProgressDialog = progressDialog
    
    requireActivity().recreate()
}
  • Activity重建完成后隐藏覆盖层:
override fun onResume() {
    super.onResume()
    if (MyApp.isLocaleRebuilding) {
        // 可选加100ms延迟,避免页面未渲染完成出现闪烁
        Handler(Looper.getMainLooper()).postDelayed({
            MyApp.tempProgressDialog?.dismiss()
            MyApp.tempProgressDialog = null
        }, 100)
        MyApp.isLocaleRebuilding = false
    }
}

内容的提问来源于stack exchange,提问作者sooyeon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 00:15:02