Android API 23以下版本如何通过代码动态切换应用语言
修复方案
问题根因
- 直接new Configuration()创建配置对象,未继承当前上下文已有的配置项,Android 5.x版本会忽略未显式设置的配置参数,导致语言修改不生效
- 仅更新了baseContext的资源配置,未同步更新Application全局上下文的配置,部分资源加载时会复用全局默认配置
- 首次启动时如果SharedPreferences未存储过语言配置,loadLocale()返回空字符串,构造Locale时参数无效,导致语言设置失败
- 未重写Activity的attachBaseContext方法,Activity创建/重建时系统会恢复默认配置,覆盖你之前设置的语言
代码修改
1. 修改MainActivity代码
public class MainActivity extends AppCompatActivity { PreferenceRepository preferenceRepository; @SuppressLint({"NonConstantResourceId", "SourceLockedOrientationActivity"}) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); preferenceRepository = new PreferenceRepository(this); setContentView(R.layout.activity_main); // 初始化控件 RadioButton GeLang = findViewById(R.id.GeorgianLang); RadioButton EnLang = findViewById(R.id.EnglishLang); RadioGroup LanguageApp = findViewById(R.id.Language); // 根据当前语言选中对应单选按钮 if (Locale.getDefault().getDisplayLanguage().equals("ქართული")){ GeLang.setChecked(true); } else { EnLang.setChecked(true); } // 选中后切换语言 LanguageApp.setOnCheckedChangeListener((LanguageApp1, i) -> { switch (i) { case R.id.GeorgianLang: setLocale("ka"); recreate(); break; case R.id.EnglishLang: setLocale("en"); recreate(); break; } }); } @Override protected void attachBaseContext(Context newBase) { PreferenceRepository tempRepo = new PreferenceRepository(newBase); String lang = tempRepo.loadLocale(); if (TextUtils.isEmpty(lang)) { super.attachBaseContext(newBase); return; } Locale locale = new Locale(lang); Locale.setDefault(locale); Resources res = newBase.getResources(); Configuration config = new Configuration(res.getConfiguration()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { config.setLocale(locale); } else { config.locale = locale; } Context context = newBase.createConfigurationContext(config); super.attachBaseContext(context); } // 更新配置并加载选中的语言 private void setLocale(String language) { // 处理空值,默认取系统当前语言 if (TextUtils.isEmpty(language)) { language = Locale.getDefault().getLanguage(); } Locale locale = new Locale(language); Locale.setDefault(locale); Resources resources = getResources(); Configuration config = resources.getConfiguration(); // 兼容低版本API if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { config.setLocale(locale); } else { config.locale = locale; } // 更新当前上下文配置 resources.updateConfiguration(config, resources.getDisplayMetrics()); // 同步更新全局Application配置 getApplicationContext().getResources().updateConfiguration(config, getApplicationContext().getResources().getDisplayMetrics()); preferenceRepository.setLocale(language); } }
2. PreferenceRepository代码无需调整,如需指定默认语言可修改loadLocale方法:
public String loadLocale() { // 示例:默认设置为英文就传入"en",留空则默认取系统语言 return mySharedPref.getString("My_Language", ""); }
额外注意事项
- 确保格鲁吉亚语资源文件夹命名为
res/values-ka,不要添加多余的地区后缀,Android 5.x对带地区的资源匹配逻辑存在兼容问题 - 如果应用存在多个Activity,建议把attachBaseContext重写、setLocale逻辑封装到BaseActivity中,所有Activity继承BaseActivity即可统一适配
- 切换语言调用recreate()会触发页面重绘,可根据需要添加过渡动画避免闪屏
内容的提问来源于stack exchange,提问作者Ksardas Freeman
相关产品推荐
相关产品推荐

