重启App后调用AdMob方法触发Locale配置异常问题
问题背景
我完全理解你的困扰:单Activity架构的多语言应用,切换语言后把设置存在SharedPreferences里,启动时恢复Locale一切正常,但销毁重启后调用AdMob的MobileAds.initialize()或AdLoader加载广告,就会触发语言自动跳回英文,而且SharedPreferences的设置根本没被改动,试过把Locale代码移到Application、用lingver库重构都没用,禁用AdMob就正常——显然是AdMob SDK和自定义Locale逻辑的冲突在作祟。
问题根源分析
你使用的AdMob版本19.6.0是比较老旧的版本了,这个版本的SDK内部大概率存在一个bug:初始化过程中会悄悄修改应用的Configuration或全局Locale设置,没有尊重应用自定义的Locale配置,反而强制使用了系统默认或者SDK内部预设的英文Locale,导致后续新创建的Fragment都继承了这个被篡改的配置。
可行解决方案
1. 优先升级AdMob SDK版本(最推荐)
旧版本SDK的很多兼容性问题在新版本中已经被修复,建议直接升级到较新的稳定版,比如22.0.0及以上(可以根据Google官方最新稳定版调整)。
修改你的build.gradle(Module级别)中的依赖:
dependencies { // 替换旧版本为新版本 implementation 'com.google.firebase:firebase-ads:22.0.0' }
升级后重新同步项目,测试重启后的语言状态,大概率能直接解决问题。
2. 初始化AdMob后强制重置Locale(兼容旧SDK)
如果暂时无法升级SDK,可以在AdMob初始化完成后,再次手动恢复自定义Locale,覆盖SDK可能做出的修改。
在你的MainApplication的onCreate方法中调整逻辑顺序:
@Override public void onCreate() { super.onCreate(); // 第一步:先恢复自定义Locale String savedLang = SettingsPrefsGet.getString(this, SettingCons.INTERFACE_LANGUAGE, SettingCons.LANG_ENGLISH); resetAppLocale(this, savedLang); // 第二步:初始化AdMob MobileAds.initialize(this); // 第三步:再次重置Locale,确保AdMob的操作不会覆盖我们的设置 resetAppLocale(this, savedLang); } // 封装重置Locale的工具方法,兼容Android 7.0+ private void resetAppLocale(Context context, String lang) { Locale targetLocale = new Locale(lang); Locale.setDefault(targetLocale); Resources res = context.getResources(); Configuration config = res.getConfiguration(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { config.setLocales(new LocaleList(targetLocale)); context.createConfigurationContext(config); } else { config.locale = targetLocale; res.updateConfiguration(config, res.getDisplayMetrics()); } }
3. 重写Activity的attachBaseContext统一管理Locale(彻底解决Context级别的Locale问题)
单Activity架构下,所有Fragment都是依附于这个Activity的Context创建的,重写attachBaseContext方法,确保每次创建Context时都强制使用自定义Locale,这样不管第三方SDK怎么修改全局配置,新的Fragment都会拿到正确语言的Context。
在你的主Activity中添加以下代码:
public class MainActivity extends AppCompatActivity { @Override protected void attachBaseContext(Context newBase) { // 读取保存的语言设置 String savedLang = SettingsPrefsGet.getString(newBase, SettingCons.INTERFACE_LANGUAGE, SettingCons.LANG_ENGLISH); Locale targetLocale = new Locale(savedLang); // 创建带有自定义Locale的Context Context updatedContext = updateLocaleContext(newBase, targetLocale); super.attachBaseContext(updatedContext); } // 适配不同Android版本的Locale更新逻辑 private Context updateLocaleContext(Context context, Locale locale) { Locale.setDefault(locale); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Configuration config = new Configuration(context.getResources().getConfiguration()); config.setLocales(new LocaleList(locale)); return context.createConfigurationContext(config); } else { Resources resources = context.getResources(); Configuration config = resources.getConfiguration(); config.locale = locale; resources.updateConfiguration(config, resources.getDisplayMetrics()); return context; } } }
这个方法能从Context的根源上保证语言设置的正确性,即使AdMob修改了全局配置,新创建的Fragment也不会受影响。
4. 明确设置AdMob广告请求的语言
额外补充:可以在创建AdRequest时明确指定语言,避免SDK自动推断语言时产生冲突:
// 读取保存的语言代码 String savedLang = SettingsPrefsGet.getString(this, SettingCons.INTERFACE_LANGUAGE, SettingCons.LANG_ENGLISH); // 创建广告请求时指定语言 AdRequest adRequest = new AdRequest.Builder() .setLanguage(savedLang) // 传入"zh"、"en"等语言代码 .build(); // 用这个请求加载广告 AdLoader adLoader = new AdLoader.Builder(this, "your-ad-unit-id") // ...其他配置 .build(); adLoader.loadAd(adRequest);
总结
优先尝试升级AdMob SDK版本,这是最彻底的解决方式;如果无法升级,结合初始化后重置Locale和重写attachBaseContext的方法,应该能完全解决这个问题。
内容的提问来源于stack exchange,提问作者Morteza Taghizadeh

