前言

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 文件目录是这样的:

d02de6fb28a3

image.png

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 目录是这样的:

d02de6fb28a3

image.png 将 raw 转换成 InputStream 代码如下:

InputStream mInputStream = context.getApplicationContext().getResources().openRawResource(R.raw.…);

重点还是获得 applicationContext

总结

在 Android 8.0 国际化的时候,所有需要 context 的地方必须用 applicationContext。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐