受书法启发,我最终创建了一个上下文包装器。就我而言,我需要覆盖系统语言,以便为我的应用程序用户提供更改应用程序语言的选项,但是可以使用您需要实现的任何逻辑对其进行自定义。
import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Build;
import java.util.Locale;
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
@SuppressWarnings("deprecation")
public static ContextWrapper wrap(Context context, String language) {
Configuration config = context.getResources().getConfiguration();
Locale sysLocale = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
sysLocale = getSystemLocale(config);
} else {
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.equals("") && !sysLocale.getLanguage().equals(language)) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setSystemLocale(config, locale);
} else {
setSystemLocaleLegacy(config, locale);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context = context.createConfigurationContext(config);
} else {
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
return new MyContextWrapper(context);
}
@SuppressWarnings("deprecation")
public static Locale getSystemLocaleLegacy(Configuration config){
return config.locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static Locale getSystemLocale(Configuration config){
return config.getLocales().get(0);
}
@SuppressWarnings("deprecation")
public static void setSystemLocaleLegacy(Configuration config, Locale locale){
config.locale = locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static void setSystemLocale(Configuration config, Locale locale){
config.setLocale(locale);
}
}
并注入您的包装,在每个活动中添加以下代码:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr"));
}
更新23/09/2020
例如,如果覆盖应用主题以应用黑暗模式,则ContextThemeWrapper将破坏语言设置,因此将以下代码添加到您的Activity中以重置所需的语言环境
@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
Locale locale = new Locale("fr");
overrideConfiguration.setLocale(locale);
super.applyOverrideConfiguration(overrideConfiguration);
}
UPDATE 10/19/2018
有时在方向改变或活动暂停/恢复后,Configuration对象将重置为默认系统Configuration,即使我们使用法文“ fr”语言环境包装上下文,结果我们仍会看到应用程序显示英文“ en”文本。因此,作为一种好的做法,请不要在活动或片段的全局变量中保留Context / Activity对象。
此外,在MyBaseFragment或MyBaseActivity中创建并使用以下内容:
public Context getMyContext(){
return MyContextWrapper.wrap(getContext(),"fr");
}
这种做法将为您提供100%无错误的解决方案。