昨天組里的同事遇到一些切換多語言的細節問題,發現在Android N版本上配置應用內多語言沒有生效,正好拿出來做為一個面試題講解一下。
面試題:如何實現應用內多語言切換?
我們知道Android的多語言實現很簡單,可以在不同的語言環境下使用不同的資源。在不同的res/value-xx下放置不同語言的strings.xml實現字符的本地化,而這個value-xx目錄的選擇是根據Resource中的Configuration.Locale這項的值來決定的。如zh中文,就會選擇value-zh目錄,如果沒有匹配到(即APK中沒有value-zh目錄)就使用默認的value目錄中的字符資源。
其實最終實現字符串的選擇都是在Assets這個類中,通過Native的方法來加載相應的字符串資源。
然而,我們還是會有一些業務場景需要不根據Android系統的Locale配置就改變應用的語言。實現的方式也很簡單,直接調用Android開放的接口Resources.updateConfiguration:
public static void changeSystemLanguage(Context context, String language) {
if (context == null || TextUtils.isEmpty(language)) {
return;
}
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
if (Locale.SIMPLIFIED_CHINESE.getLanguage().equals(language)) {
config.locale = Locale.SIMPLIFIED_CHINESE;
} else {
config.locale = new Locale(language);
}
resources.updateConfiguration(config, null);
}
上面的代碼,我們可以在應用內通過language的值指定是顯示哪種語言,當然language值我們需要保存在Preferences或者數據庫中。
好像很簡單,我們的項目為什么還會出現問題呢?而且大家都不知道如何下手,因為在Android N之前的版本都是可以正常切換語言的。后來我跟了一下,發現在MainActivity和SplashActivity這些Activity有繼承了自已擴展的BaseActivity,而這個BaseActivity有這樣一段代碼:
@Override
public Resources getResources() {
Resources res = super.getResources();
Configuration config = new Configuration();
config.setToDefaults();
res.updateConfiguration(config, res.getDisplayMetrics());
return res;
}
config.setToDefaults會將Locale的值設為null,而再調用updateConfiguration可能會根據Android系統的語言重新設置Resources中的Locale。好吧,只是假設,還沒有看到Android N的源代碼。不過去掉這段代碼后,在Android N(Preview)手機上切換語言正常了。
小結
今天遇到的問題,是以前遺留的代碼埋下的坑終于暴露出來,也是這個項目缺乏代碼審查(Code Review)機制的結果。找了幾個人也無法說清覆寫getResources這個方法的用意,最終也只能按歷史問題處理了,是歷史總有一些說不清楚的事,對吧。
回到這個面試題,現在你知道了可以在應用內切換語言(當然也可以修改Configuration的其他值),那么你有沒有想過,如果不知道這個updateConfiguration的存在,你會怎么實現這個需求呢?或者說沒有人和你說過updateConfiguration,你能找到它嗎?