Android首次调用AppCompatDelegate.setApplicationLocales忽略configChanges致Activity重建
应用内语言偏好首次设置时Activity被强制重建的问题及临时解决方法
我按官方文档实现了应用内语言偏好功能:用户首次打开应用时,先进入语言选择Activity,选完语言后调用以下代码通知系统语言变更:
// 该代码在onCreate()之后的某个时机调用 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val selectedLanguageIso = "en" val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(selectedLanguageIso) AppCompatDelegate.setApplicationLocales(appLocale) }
为避免语言变更时重建Activity,我在Manifest中给LanguageActivity添加了配置:
<activity android:name=".LanguageActivity" android:screenOrientation="portrait" android:configChanges="layoutDirection|locale"/>
但仅首次调用AppCompatDelegate.setApplicationLocales时,系统会忽略这个配置,依然重建Activity,导致页面闪烁,之后才跳转到下一个页面。后续手动更改语言时,该配置能正常生效,不会触发重建。
补充背景:我关闭了自动区域设置存储,所以首次启动应用时Android没有预设语言,必须手动设置,这可能和问题有关:
<service android:name="androidx.appcompat.app.AppLocalesMetadataHolderService" android:enabled="false" android:exported="false"> <meta-data android:name="autoStoreLocales" android:value="false" /> </service>
请问有没有人遇到过同样的问题?
临时解决方案
我在首个Activity的ViewModel中通过InitializePerAppLanguageUseCase提前初始化语言设置,避免首次调用时的重建问题:
ViewModel代码
init { initPerAppLanguage() //...其他初始化逻辑 } private fun initPerAppLanguage() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { initializePerAppLanguage() // 调用下面的UseCase } }
UseCase代码
/** * 检查是否需要初始化应用语言设置 * * 由于首次调用`AppCompatDelegate.setApplicationLocales`时,系统会忽略Manifest中的`android:configChanges="layoutDirection|locale"`配置, * 导致首次打开应用时Activity重启,所以需要手动提前初始化一次语言设置,让API处于"已初始化"状态,后续调用就不会再触发重建。 * * @see AppCompatDelegate.setApplicationLocales */ class InitializePerAppLanguageUseCase( private val defaultDeviceLanguage: String, // 对应Locale.getDefault().language private val appSettings: AppSettings ) { @RequiresApi(Build.VERSION_CODES.TIRAMISU) operator fun invoke() { if (!appSettings.isBoardingDone()) { // SupportedLanguages是应用支持的语言列表 if (SupportedLanguages.languages.contains(defaultDeviceLanguage)) { setSelectedLanguage(defaultDeviceLanguage) } else { // 如果设备语言不在支持列表中,默认回退到英文 setSelectedLanguage("en") } } } private fun setSelectedLanguage(isoCode: String) { val localeListCompat = LocaleListCompat.forLanguageTags(isoCode) AppCompatDelegate.setApplicationLocales(localeListCompat) } }
内容的提问来源于stack exchange,提问作者JacksOnF1re
相关产品推荐
相关产品推荐

