前言
Android 8.0 发布已经有一段时间了,本文不讲新功能,讲讲资源国际化方面 Android 8.0 的踩坑及填坑经历。
项目中要求应用内切换语言,并且不同语言也对应不同的语言字体(参考了这两个库 perfectLanguageUpdateNoNeedRestart、FontometricsLibrary ),不同语言对应不同的布局文件。
三个部分
- 切换语言
- 切换 layout 文件
- 切换 raw 文件
切换语言
Android 8.0 之前切换语言只需要以下代码
Resources resources = getContext().getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
config.locale = Locale.ENGLISH; // 应用用户选择语言
resources.updateConfiguration(config, dm);
Android 8.0 切换语言需要以下代码
Resources resources = getApplicationContext().getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleList localeList = new LocaleList(locale);
LocaleList.setDefault(localeList);
config.setLocales(localeList);
getApplicationContext().createConfigurationContext(config);
}
Locale.setDefault(locale);
resources.updateConfiguration(config, dm);
重点: 确保 applicationContext
代替所有其它类型的 context
。(至于针对 Android N 的那几行代码,实测好像没什么影响。)
切换 layout 文件
项目需求比较复杂,我的 layout 文件目录是这样的:
Android 8.0 之前,执行了上面代码,当你切换界面的时候,应该能显示对应语言下的
layout
文件。比如把 Locale
设置成中文简体,R.layout
文件将调用 layout-zh-rCN
目录下的界面,但是 Android 8.0 仍然执行了默认 layout 目录下面的界面。解决思路仍然是用 applicationContext
替代 context
。项目里对 layout 文件的使用有两处:
- Activity 的
setContentView(R.layout.…)
- Fragment 的
inflater.inflate(R.layout.…, container, false)
针对 Fragment 容易解决,我发现 inflate 有两个重载方法
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {……}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {……}
其中第二个方法的第一个参数 parser
, 可以这样获得:getContext().getApplicationContext().getResources().getLayout(R.layout.…)
, 于是在 fragment
中获得布局文件就可以这样写 inflater.inflate(getContext().getApplicationContext().getResources().getLayout(R.layout.……), container, false);
fragment
的问题解决了,activity
的 setContentView
确没有相应的方法。解决方案也很粗暴,就是在 activity
中添加一个充满全局 fragment
,然后将原 activity
的代码交由 fragment
管理,在 fragment
中获取多资源布局。
切换 raw 文件
为了给不同语言设置不同字体文件,参考并且修改了 FontometricsLibrary 的代码,现在我的 raw
目录是这样的:
raw
转换成 InputStream
代码如下:
InputStream mInputStream = context.getApplicationContext().getResources().openRawResource(R.raw.…);
重点还是获得 applicationContext
总结
在 Android 8.0 国际化的时候,所有需要 context
的地方必须用 applicationContext
。