Android多语言适配的示例代码(兼容7.0+)
一、前言
1、安卓系统本身对多语言适配就提供了一套框架和API。我们就直接用就可以了。
2、更换语言必须recreateActivity。目前,没见过可以不重建的方法。常用App,也都是重建的,可以看的到。
3、兼容性问题。现在越来越多设备都是安卓7.0+新手机的安卓版本会更高(安卓8.0+),所以适配是必要的。
4、目前,网上大部分相关文章都是不兼容7.0+的,具体做法一搜一大把。
二、具体做法
1、多语言文件
文件夹命名参考下面博客(网上有很多):
多国语言value文件夹命名
value默认放英文的资源文件,简体中文文件夹命名为values-zh-rCN,不需要翻译的设置translatable如下:
YouAppEnglishName
2、多语言工具类
publicclassLanguageUtils{
publicstaticfinalStringCHINESE_SIMPLE="zh_CN";
publicstaticfinalStringENGLISH="en";
publicstaticfinalStringAUTO="auto";
privatestaticfinalStringTAG="LanguageUtils";
//publicstaticfinalString[]LOCALES=Utils.getContext().getResources().getStringArray(R.array.locales);
privateLanguageUtils(){
thrownewUnsupportedOperationException("ucan'tinstantiateme...");
}
publicstaticvoidsetSystemDefaultLocale(Localelocale){
}
publicstaticbooleanisSetValue(Contextcontext){
LocalecurrentLocale=context.getResources().getConfiguration().locale;
returncurrentLocale.equals(getSetLocale());
}
privatestaticLocalegetSetLocale(){
Stringlocale=SPUtils.getInstance(BaseConstants.SP.NAME_APP_SETTINGS).getString(BaseConstants.SP.KEY_LANGUAGE,LanguageUtils.AUTO);
if(locale.equals(LanguageUtils.AUTO)){
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
returnResources.getSystem().getConfiguration().getLocales().get(0);//解决了获取系统默认错误的问题
}else{
returnLocale.getDefault();
}
}
String[]array=locale.split("_");
Stringlanguage=array[0];
if(array.length>1){
Stringcountry=array[1];
returnnewLocale(language,country);
}
returnnewLocale(language);
}
publicstaticintgetSetIndex(){
StringlanguageSet=SPUtils.getInstance(BaseConstants.SP.NAME_APP_SETTINGS).getString(BaseConstants.SP.KEY_LANGUAGE,LanguageUtils.AUTO);
intlocaleIndex=0;
switch(languageSet){
caseLanguageUtils.AUTO:
localeIndex=0;
break;
caseLanguageUtils.CHINESE_SIMPLE:
localeIndex=1;
break;
caseLanguageUtils.ENGLISH:
localeIndex=2;
break;
}
returnlocaleIndex;
}
publicstaticContextwrapContext(Contextcontext){
Resourcesresources=context.getResources();
Localelocale=LanguageUtils.getSetLocale();
Configurationconfiguration=resources.getConfiguration();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
configuration.setLocale(locale);
LocaleListlocaleList=newLocaleList(locale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
}else{
configuration.setLocale(locale);
}
returncontext.createConfigurationContext(configuration);
}
publicstaticvoidapplyChange(Contextcontext){
Resourcesres=context.getResources();
DisplayMetricsdm=res.getDisplayMetrics();
Configurationconf=res.getConfiguration();
Localelocale=getSetLocale();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
conf.setLocale(locale);
LocaleListlocaleList=newLocaleList(locale);
LocaleList.setDefault(localeList);
conf.setLocales(localeList);
}else{
conf.setLocale(locale);
}
res.updateConfiguration(conf,dm);
}
}
3、代码分析&兼容7.0+
3.1、如何获取系统的语言设置,也就是7.0+你选择auto,可以正确切换。
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
returnResources.getSystem().getConfiguration().getLocales().get(0);//解决了获取系统默认错误的问题
}else{
returnLocale.getDefault();
}
看到这篇文章的你,可能已经看过网上很多其他相关的文章,应该知道,7.0+系统有个很奇怪的地方:
如果你在app内切换了语言(比如说是英文),且该语言和系统的设置(比如说是中文)不同,那么你再次切换语言并选择auto时,通过Locale.getDefault()获取会错误,或者你通过LocaleList.get(0)也是错误的,你之前选择的语言(英文)排序被提前了。有些文章的解决方案是在app打开时持久化系统设置,这样你切换app的语言就不会影响你获取系统的设置,但这样没必要,太麻烦(应该是不知道上面的方法)。
7.0+的系统设置也看的出差别,以前,设置系统语言直接选择就可以了,现在你要先添加,然后再排序,排在第一个的才是系统显示的语言!
3.2、写个BaseActivity作为所有Activity父类
新建一个BaseActivity用于继承,重写:
@Override
protectedvoidattachBaseContext(ContextnewBase){
super.attachBaseContext(LanguageUtils.wrapContext(newBase));
}
然后在切换语言后,你要recreateActivity。这个在哪调用就看具体需求了。你可以像微信那样,清空栈,然后直接重启到主界面,也可以在设置界面recreate,但栈内其他Activity,也要想办法通知recreate。
3.3、屏蔽系统设置改变
如果app的语言选项不是auto,那么系统语言设置修改时,app就不应该跟着系统变,而是按照自己设置的语言显示。写一个类继承于Application(注意要在manifest配置哦,不然无效的)
publicclassMyAppextendsApplication{
privateConfigurationdeltaConfig;
@Override
publicvoidonConfigurationChanged(ConfigurationnewConfig){
LogUtils.d(TAG,"调用了onConfigurationChanged");
intdiff=newConfig.diff(deltaConfig);
StringlanguageSet=SPUtils.getInstance(AppConstants.SP.NAME_APP_SETTINGS).getString(AppConstants.SP.KEY_LANGUAGE,LanguageUtils.AUTO);
if(languageSet.equals(LanguageUtils.AUTO)){//看app语言设置是不是auto,是的话不管,直接super
super.onConfigurationChanged(newConfig);
deltaConfig=newConfig;
}elseif(diff!=ActivityInfo.CONFIG_LOCALE){//这个Configuration更改是不是语言,不是的话,也不管
super.onConfigurationChanged(newConfig);
deltaConfig=newConfig;
}
//这里使系统设置语言无效
//相当于省略了
//else{
//return;
//}
}
@Override
publicvoidonCreate(){
super.onCreate();
//app打开时记录系统设置
deltaConfig=getApplicationContext().getResources().getConfiguration();
LanguageUtils.applyChange(getApplicationContext());
}
}
}
3.4、其他问题
Application的Context也要更新
LanguageUtils.applyChange(context); LanguageUtils.applyChange(context.getApplicationContext());
但即使这样,还是有点问题,主要在于:
如果Activity的Title你是在manifest中定义的,如下label:
那么,即使你更新了ApplicationContext,有些Activity也有可能不生效,而且每次都还不一样,这个没法复现(很迷)。不知道是不是系统bug(测试系统是一加3氢OS8.0),或者是有其他更好的写法?
针对这个问题,只要在activityoncreate()里setTitle()就好了。这样是不会有什么问题的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。