前阵子因为公司朝着国际市场的进军,上面要求做起多语言的切换(目前只要求中英双语),其中踩了不少的坑,来这边简单归纳一下。根据往常,我把本章节进行一下目录整理如下:
1、系统设置中Android 7.0 前后语言设置的区别与准备工作
2、Application与Activity两种配置修改方式
3、具体的实现
4、踩的坑
目前能想到的就这么几个,现在我们进入正文。
1、系统设置中Android 7.0 前后语言设置的区别与准备工作
我们先从系统设置来查看一下,语言切换的变化
可知,在7.0之前,是直接把你手机的语言库列表进行展示,然后在列表中进行选择。而7.0及其之后则是通过进行添加把语言库加载进来,而加载进来的一般的第一的就相当于是你的母语(譬如中文),第二的相当于是你的第二语言(譬如英文)。显示的也是根据第一条对应的语言库进行语言库填充。
准备工作大致可分为以下几个步骤:
1、添加多语言文件:在不同的 value 文件夹下(例如 value 、value-en、values-zh-rTW 文件夹)添加不同语言的 string.xml 文件。根据我的项目需求,目前只需要中英,所以对应目录建设如下,如果需要其他语言,你可以自己进行创建。
2、文件属性配置:的在AndroidManifest.xml里面进行配置,加上该权限
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
允许一个程序修改当前设置,如本地化(Allowsan application to modify the current configuration, such as locale. )
如果采用Activity的策略,则需要在AndroidManifest.xml文件里的每一个Activity进行配置,这个在下文会详细说。
3、代码里的基本逻辑:这里就很笼统,一般是选择的机制和其他辅助工具的前期准备。比如我是通过SharePreference进行记录用户选择之类的。我个人是认为这属于准备工作,所以在这边说明一下。
2、Application与Activity两种配置修改方式
总的来说,我们多语言的切换大多都是基于value文件夹下的string文件进行配置和获取。这就引伸到,我们获取这个资源的context是属于Activity还是Application了。这里我们先说一下,实现的步骤:
1、Application方式
这种方式配置简单,因为一个app只有一个application,我们针对的目标也就只有这么一个类,而且避免了一些情况下,某些activity的特殊情况造成不统一。当然,采取这种方式会带来一些问题,在我遇到的这些问题中,对应的针对方法也有(可能不够优美,或者更好的方法我没发现)。这里我把大致步骤说一下,比较重要的代码进行张贴,详细的步骤可以去搜索网上的。
先在application类中重写配置修改回调方法如下:
@Override
public void onConfigurationChanged(Configuration newConfig) {
ContextWrapper warp = LanUtils.wrap(this, LanUtils.getTargetLable());
super.onConfigurationChanged(warp.getApplicationContext().getResources().getConfiguration());
}
上面对应的方法在这里面,而LanUtils.getTargetLable()则是我记录的,已经切换的locale的记录对象,这个小伙伴们可以自行实现。下述方法因为还有其他地方用得到,所以我进行封装
当然,在application类的onCreat方法也需要进行初始化,本人采取的是这种方法。因为还有一个跟随系统的选项,因此在每次app启动创建的时候进行语言选择一次。至此,当你把工具类实现了,就可以实现多语言切换了,但是这只能修改以application对应的context进行资源索引的更新,而布局里的采取的还是以activity,这时候你需要去你的baseActivity里重写该方法:
@Override
protected void attachBaseContext(Context newBase) {
Context context = LanUtils.wrap(newBase, LanUtils.getTargetLable());
super.attachBaseContext(context);
}
这样在每次activity获取基本上下文的时候,才能将activity的context进行配置更新。当然,这种方式需要reCreate对应的已存在的activity才能够较好地实现目标状态。
2、Activity方式
这个方式最大的优点就是可以不进行activity的重建,而且实现也很简单,但是隐患也相对多。这里我们先介绍一个属性:
Configuration 这个类描述了设备的所有配置信息,这些配置信息会影响到应用程序检索的资源。包括了用户指定的选项(locale和scaling)也包括设备本身配置(例如input modes,screen size and screen orientation).可以在该类里查看所有影响Configuration Change 的属性。
横竖屏切换是我们最常见的影响配置变化的因素,还有很多其他影响配置的因素有语言的更改(例如中英文切换)、键盘的可用性(这个没理解)等
常见的引发Configuration Change的属性:
横竖屏切换:android:configChanges="orientation"
键盘可用性:android:configChanges="keyboardHidden"
屏幕大小变化:android:configChanges="screenSize"
语言的更改:android:configChanges="locale"
在程序运行时,如果发生Configuration Change会导致当前的Activity被销毁并重新创建,即先调用onDestroy紧接着调用onCreate()方法。重建的目的是为了让应用程序通过自动加载可替代资源来适应新的配置。
当我们没有配置的时候,上述的变化都会造成activity的重建。因此我们在每个activity都需要补上对应属性,如:
android:configChanges="orientation|screenSize|locale"
配置完后,我们在activity就不需要重建(对应是否会重建需要针对具体属性和场景,请自行搜索其他情况,这里不详细说明),只走对应回调方法即可(同理,可针对横竖屏切换等的场景)
同样,在这种方式下就可以在语言切换的时候,传递activity的上下文context进行多语言配置更新。
3、两种方式的优缺点
从上头我们可以知道,application方式,目标单一,比较不会造成混乱,而且在AndroidManifest.xml配置文件也是比较清晰的。而activity方式,则是无需重建activity,而且配置步骤十分简单。然而二者的缺点也是不可忽视的:
application:
需要重建activity,造成损耗;
当你生命周期管理不够好的时候,很容易在切换语言造成异常(当然这个不是它的锅,说明你自己生命周期管理不善);
当横竖屏切换、webview相关问题的时候也会出现语言设置失效。
activity:
AndroidManifest.xml里需要对每个activity进行相关属性配置,使得结构远不如上一个清晰;
Google官方并不推荐为了某单一配置变化而阻止重建进行自我配置,理由有几个,有网友简单归纳几点:
1. 配置改变和资源调整的问题,因为用这个方法我们需要自己往onConfigurationChanged()里写代码,保证所用资源和设备的 当前配置一致,如果一个马虎程序很容易出现资源指定的bugs,原文:
Google engineers,however, discourage its use. The primary concern is that it requires youto handle device configuration changes manually in code. Handling configuration changes requires you to take many additional steps to ensure that each and every string, layout, drawable, dimension, etc.remains in sync with the device's current configuration, and if you aren't careful, your application can easily have a whole series of resource-specific bugs as a result.——Handling Configuration Changes With Fragments
2. there are other configuration changes that you cannot prevent from restarting your application.有些configuration changes没法阻止应用重启。(是说的有些android:configChanges的属性值对避免重建无效?不知道理解是否正确)
3. 很多开发人员会错误指定android:configChanges="orientation"来防止activity被销毁或重建这种不可预知的情况。但是引起Configuration Changes的情况很多,不止是屏幕旋转。比如修改设备默认语言,修改设备默认字体比例等等都可会引起配置改变。这种方法只对当前设置的配置有效,除非在manifest里把所有配置都列全。
4. 当用户离开应用,在回到应用前被销毁的话,例如点击了屏幕的Home键或者有个电话打进来,用户很久之后才回到应用程序,但是在此之前系统因为资源紧张而销毁了应用进程,当用户返回还是要重新创建activity,问题等于没解决。
综上,取用哪种方法可以根据你的需求所决定。
3、具体的实现
上文已经说了实现方式的不同与各自的方法,自然也需要对应的实现方式。先说明以下,由于本人的app主活动需要一直存在,所以一开始设计的时候主活动的默认运行与界面复杂度都尽量降低,因此重建的成本比较低,采用了第一种方法,对应的工具类多少也有点定制化了。
首先,在application里onCreat进行初始化:
在我们每次进行语言选择的时候,就需要对本地的配置进行语言选择更新,其中以7.0 为分界线,7.0之前与7.0+是存在差别的:
而跟随系统的时候,就需要进行设置监听:
<receiver
android:name=".application.LocalChangeReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
public class LocalChangeReceiverextends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
//如果是跟随系统,则进行应用重启
String userSelectLanguage = LocalModel.getLanguageSelect();
if (LanUtils.DefaultLanguage.equals(userSelectLanguage)) {
exit...
}else {
LanUtils.languageSelect(userSelectLanguage,true);}}}
}
对应的逻辑可以自行完善
4、踩的坑
第1个是横竖屏切换,造成了多语言设置的失效
由于项目采用了公司的前辈自己封装的框架,造成application类被其隐藏,只有对应主要生命周期回调方法,造成application的onConfigurationChanged无法重写,所以在横竖屏切换的时候发生该问题。
解决的方法很粗暴,由于就是在activity的每次onCreat的时候进行context的语言与目标语言是否一致,如果一致就不操作,不一致就进行语言选择操作。
第2个是WebView,造成了多语言设置的失效
根据网上搜索,该问题是发生在Android N之后的版本,原因就是:
webview 在Android N之后,webview的相关类以及相关jar的修改
Android N 之前:
Android的WebView是使用webkit构建的。虽然它最初是AOSP的一部分,但是从KitKat开始,决定分离出WebView一个名为Android System WebView的组件。它基本上是一个Android系统应用程序,预装了Android设备。它会像其他系统应用程序(如Google Play服务和Play商店应用程序)一样定期更新。您可以在已安装的系统应用列表中看到它:
Android 7.0之后:
Chrome应用将用于呈现WebView第三方Android应用中的任何/所有内容。在具有Android N开箱即用的手机中,Android WebView系统应用
解决方法:
1、在对应的application的onCreat里补充上:new WebView(this).destroy();
2、在所有Activity下重设语言。StackOverFlow的回答中说也可以只在含有WebView的Activity中重设。这里建议,还是全设置掉好一点。在你的BaseActivity中,并且在调用setContentView之前调用如下代码设置你的Local。
不过本人切换语言有走activity重建,所以,并没有在每个activity进行重设置。而是在对应activity的初始化(onCreat)进行语言判断与设置。为了在其前后创建的活动同样进行语言判断与设置。
到这里,大致就把多语言设置进行简单的说明。主要的步骤很简单,但是里面的坑不少,本人遇到了相当一部分,但是应该还没完全遇到,结合其他博客所阐述的情况,在这里进行一些归纳与总结,作为自己的笔记也希望能给你们提供参考,如有疏漏或者错误,希望不吝指正,万分感激🙏
注:本人所写的工具类在如下网盘,没有完全独立,简单修改一下应该是适用的,希望能够帮到你
链接:百度网盘共享地址 密码:d9nr
参考博文:
---------------------
作者: 回归的阿廖 来源:CSDN 题目:Android Configuration change引发的问题及解决方法
链接:https://blog.csdn.net/aliaooooo/article/details/23606179
---------------------
作者:拜天地 来源:CSDN 题目:【安卓学习之常见问题】 多国语言横竖屏时,自动切换到默认语言(android:configChanges的使用)
链接:https://blog.csdn.net/ljb568838953/article/details/77005347
---------------------
作者:火凤燎原 来源:CSDN 题目:Android7(N)中webview导致应用内语言切换失效
链接:https://blog.csdn.net/ArimaKisho/article/details/79798752