android更换语言
工具类:
public class MultiLanguageUtil {
private static final String TAG = "MultiLanguageUtil";
private static MultiLanguageUtil instance;
private Context mContext;
public static final String SAVE_LANGUAGE = "save_language";
public static void init(Context mContext) {
if (instance == null) {
synchronized (MultiLanguageUtil.class) {
if (instance == null) {
instance = new MultiLanguageUtil(mContext);
}
}
}
}
public static MultiLanguageUtil getInstance() {
if (instance == null) {
throw new IllegalStateException("You must be init MultiLanguageUtil first");
}
return instance;
}
private MultiLanguageUtil(Context context) {
this.mContext = context;
}
/**
* 设置语言
*/
public void setConfiguration() {
Locale targetLocale = getLanguageLocale();
Configuration configuration = mContext.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(targetLocale);
} else {
configuration.locale = targetLocale;
}
Resources resources = mContext.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);//语言更换生效的代码!
}
/**
* 如果不是英文、简体中文、繁体中文,默认返回简体中文
*
* @return
*/
private Locale getLanguageLocale() {
int languageType = CommSharedUtil.getInstance(mContext).getInt(MultiLanguageUtil.SAVE_LANGUAGE, 0);
if (languageType == LanguageType.LANGUAGE_CHINESE) {
return new Locale("en", "ZA");
} else {
Locale sysLocale= Locale.CHINESE;
return sysLocale;
}
private String getSystemLanguage(Locale locale) {
return locale.getLanguage() + "_" + locale.getCountry();
}
//以上获取方式需要特殊处理一下
public Locale getSysLocale() {
Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
locale = LocaleList.getDefault().get(0);
} else {
locale = Locale.getDefault();
}
return locale;
}
/**
* 更新语言
*
* @param languageType
*/
public void updateLanguage(int languageType) {
CommSharedUtil.getInstance(mContext).putInt(MultiLanguageUtil.SAVE_LANGUAGE, languageType);
MultiLanguageUtil.getInstance().setConfiguration();
}
public String getLanguageName(Context context) {
int languageType = CommSharedUtil.getInstance(context).getInt(MultiLanguageUtil.SAVE_LANGUAGE,LanguageType.LANGUAGE_UYGUR);
if (languageType == LanguageType.LANGUAGE_CHINESE) {
return mContext.getString(R.string.setting_language_chinese);
}
return mContext.getString(R.string.setting_language_uygur);
}
/**
* 获取到用户保存的语言类型
* @return
*/
public int getLanguageType() {
int languageType = CommSharedUtil.getInstance(mContext).getInt(MultiLanguageUtil.SAVE_LANGUAGE, LanguageType.LANGUAGE_UYGUR);
if (languageType == LanguageType.LANGUAGE_CHINESE) {
return LanguageType.LANGUAGE_CHINESE;
}
return languageType;
}
public static Context attachBaseContext(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return createConfigurationResources(context);
} else {
MultiLanguageUtil.getInstance().setConfiguration();
return context;
}
}
@TargetApi(Build.VERSION_CODES.N)
private static Context createConfigurationResources(Context context) {
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale=getInstance().getLanguageLocale();
configuration.setLocale(locale);
return context.createConfigurationContext(configuration);
}
}
使用方法:
1.在MyApplication里加如下代码:
MultiLanguageUtil.init(this);//初始化
2.在BaseActivity中加入:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MultiLanguageUtil.attachBaseContext(newBase));
}
遇到的问题:
1. 横竖屏切换(屏幕旋转)导致多语言(国际化)的设置失效
原因:当屏幕旋转横竖屏切换时,Activity的onConfigurationChanged方法使用了系统的语言设置,Activity中onConfigurationChanged的源码如下:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
if (mResources != null) {
// The real (and thus managed) resources object was already updated
// by ResourcesManager, so pull the current metrics from there.
final DisplayMetrics newMetrics = super.getResources().getDisplayMetrics();
mResources.updateConfiguration(newConfig, newMetrics);
}
}
从上面的代码中我们可以看到newConfig取的是系统的,这就解释了为什么APP明明设置成了繁体,但是打开一个横屏页面之后,发现APP又重置成了简体,就是这个方法导致的。
所以我们只需要在onConfigurationChanged方法中,重新设置为我们用户选择的语言配置就可以了。因为要在所有的Activity中的onConfigurationChanged中设置会有些麻烦,我们可以在application中的onConfigurationChanged方法中统一设置,这样就可以解决屏幕旋转造成的多语言失效问题。
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
MultiLanguageUtil.getInstance().setConfiguration();
}
2. 打开有 webview 的Activity会导致多语言失效,发生在Android7.0以上
原因:可能是webview在加载的过程中也会重新设置系统的语言,这样因为打开网站可能有英文版的和中文的。
解决方案,既然很多情况下都会造成多语言失效,不如我们统一在BaseActivity的onCreate方法中都设置
LanguageUtil.getInstance().setConfiguration();
当然如果有些Activity不是继承子BaseActivity,我们依然可以在application中的onCreate方法中使用这样的方式来拿到整个应用的所有activity的生命周期方法,然后在这样设置:
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
MultiLanguageUtil.getInstance().setConfiguration();
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
3. 使用微信开源的热修复框架Tinker,打了包含资源的补丁之后会导致多语言失效
在试用的过程中遇到如果打了包含资源string文件的补丁之后,会导致多语言失效,本来选的繁体变成了简体语言,同时无论你怎么切换语言,都没有生效。这属于Tinker的bug,已经有人在Tinker的github主页上反馈了,但是这个issue 任然没有关闭:(https://github.com/Tencent/tinker/issues/302) 。
4.在build.gradle文件配置问题:
第一个是版本问题,这个问题的回答比较多,我遇到的问题如下,设置了:
image.png
导致语言切换无作用,这是在对接各大手机市场的平台时配置的,所以注意这个问题。