Android多語言適配的示例代碼(兼容7.0+)
一、前言
1、安卓系統(tǒng)本身對多語言適配就提供了一套框架和API。我們就直接用就可以了。
2、更換語言必須recreate Activity。目前,沒見過可以不重建的方法。常用App,也都是重建的,可以看的到。
3、兼容性問題。現(xiàn)在越來越多設(shè)備都是安卓7.0+新手機(jī)的安卓版本會更高(安卓8.0+),所以適配是必要的。
4、目前,網(wǎng)上大部分相關(guān)文章都是不兼容7.0+的,具體做法一搜一大把。
二、具體做法
1、多語言文件
文件夾命名參考下面博客(網(wǎng)上有很多):
value默認(rèn)放英文的資源文件,簡體中文文件夾命名為values-zh-rCN,不需要翻譯的設(shè)置translatable如下:
<string name="app_name_english" translatable="false">You App English Name</string>
2、多語言工具類
public class LanguageUtils { public static final String CHINESE_SIMPLE = "zh_CN"; public static final String ENGLISH = "en"; public static final String AUTO = "auto"; private static final String TAG = "LanguageUtils"; //public static final String[] LOCALES = Utils.getContext().getResources().getStringArray(R.array.locales); private LanguageUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } public static void setSystemDefaultLocale(Locale locale) { } public static boolean isSetValue(Context context) { Locale currentLocale = context.getResources().getConfiguration().locale; return currentLocale.equals(getSetLocale()); } private static Locale getSetLocale() { String locale = 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) { return Resources.getSystem().getConfiguration().getLocales().get(0);//解決了獲取系統(tǒng)默認(rèn)錯誤的問題 } else { return Locale.getDefault(); } } String[] array = locale.split("_"); String language = array[0]; if (array.length > 1) { String country = array[1]; return new Locale(language, country); } return new Locale(language); } public static int getSetIndex() { String languageSet = SPUtils.getInstance(BaseConstants.SP.NAME_APP_SETTINGS).getString(BaseConstants.SP.KEY_LANGUAGE, LanguageUtils.AUTO); int localeIndex = 0; switch (languageSet) { case LanguageUtils.AUTO: localeIndex = 0; break; case LanguageUtils.CHINESE_SIMPLE: localeIndex = 1; break; case LanguageUtils.ENGLISH: localeIndex = 2; break; } return localeIndex; } public static Context wrapContext(Context context) { Resources resources = context.getResources(); Locale locale = LanguageUtils.getSetLocale(); Configuration configuration = resources.getConfiguration(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { configuration.setLocale(locale); LocaleList localeList = new LocaleList(locale); LocaleList.setDefault(localeList); configuration.setLocales(localeList); } else { configuration.setLocale(locale); } return context.createConfigurationContext(configuration); } public static void applyChange(Context context) { Resources res = context.getResources(); DisplayMetrics dm = res.getDisplayMetrics(); Configuration conf = res.getConfiguration(); Locale locale = getSetLocale(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { conf.setLocale(locale); LocaleList localeList = new LocaleList(locale); LocaleList.setDefault(localeList); conf.setLocales(localeList); } else { conf.setLocale(locale); } res.updateConfiguration(conf, dm); } }
3、代碼分析&兼容7.0+
3.1、如何獲取系統(tǒng)的語言設(shè)置,也就是7.0+你選擇auto,可以正確切換。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return Resources.getSystem().getConfiguration().getLocales().get(0);//解決了獲取系統(tǒng)默認(rèn)錯誤的問題 } else { return Locale.getDefault(); }
看到這篇文章的你,可能已經(jīng)看過網(wǎng)上很多其他相關(guān)的文章,應(yīng)該知道,7.0+系統(tǒng)有個很奇怪的地方:
如果你在app內(nèi)切換了語言(比如說是英文),且該語言和系統(tǒng)的設(shè)置(比如說是中文)不同,那么你再次切換語言并選擇auto時,通過Locale.getDefault()獲取會錯誤,或者你通過LocaleList.get(0)也是錯誤的,你之前選擇的語言(英文)排序被提前了。有些文章的解決方案是在app打開時持久化系統(tǒng)設(shè)置,這樣你切換app的語言就不會影響你獲取系統(tǒng)的設(shè)置,但這樣沒必要,太麻煩(應(yīng)該是不知道上面的方法)。
7.0+的系統(tǒng)設(shè)置也看的出差別,以前,設(shè)置系統(tǒng)語言直接選擇就可以了,現(xiàn)在你要先添加,然后再排序,排在第一個的才是系統(tǒng)顯示的語言!
3.2、寫個BaseActivity作為所有Activity父類
新建一個BaseActivity用于繼承,重寫:
@Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(LanguageUtils.wrapContext(newBase)); }
然后在切換語言后,你要recreate Activity。這個在哪調(diào)用就看具體需求了。你可以像微信那樣,清空棧,然后直接重啟到主界面,也可以在設(shè)置界面recreate,但棧內(nèi)其他Activity,也要想辦法通知recreate。
3.3、屏蔽系統(tǒng)設(shè)置改變
如果app的語言選項(xiàng)不是auto,那么系統(tǒng)語言設(shè)置修改時,app就不應(yīng)該跟著系統(tǒng)變,而是按照自己設(shè)置的語言顯示。寫一個類繼承于Application(注意要在manifest配置哦,不然無效的)
public class MyApp extends Application { private Configuration deltaConfig; @Override public void onConfigurationChanged(Configuration newConfig) { LogUtils.d(TAG, "調(diào)用了onConfigurationChanged"); int diff = newConfig.diff(deltaConfig); String languageSet = SPUtils.getInstance(AppConstants.SP.NAME_APP_SETTINGS).getString(AppConstants.SP.KEY_LANGUAGE, LanguageUtils.AUTO); if (languageSet.equals(LanguageUtils.AUTO)) {//看app語言設(shè)置是不是auto,是的話不管,直接super super.onConfigurationChanged(newConfig); deltaConfig = newConfig; } else if (diff != ActivityInfo.CONFIG_LOCALE) {//這個Configuration更改是不是語言,不是的話,也不管 super.onConfigurationChanged(newConfig); deltaConfig = newConfig; } //這里使系統(tǒng)設(shè)置語言無效 //相當(dāng)于省略了 //else{ // return; //} } @Override public void onCreate() { super.onCreate(); //app打開時記錄系統(tǒng)設(shè)置 deltaConfig = getApplicationContext().getResources().getConfiguration(); LanguageUtils.applyChange(getApplicationContext()); } } }
3.4、其他問題
Application的Context也要更新
LanguageUtils.applyChange(context); LanguageUtils.applyChange(context.getApplicationContext());
但即使這樣,還是有點(diǎn)問題,主要在于:
如果Activity的Title你是在manifest中定義的,如下label:
<activity android:name=".ui.activity.AboutActivity" android:launchMode="singleTop" android:label="@string/lable_activity_about" android:theme="@style/AppTheme.NoActionBar"/>
那么,即使你更新了ApplicationContext,有些Activity也有可能不生效,而且每次都還不一樣,這個沒法復(fù)現(xiàn)(很迷)。不知道是不是系統(tǒng)bug(測試系統(tǒng)是一加3 氫OS 8.0),或者是有其他更好的寫法?
針對這個問題,只要在activity oncreate() 里setTitle()就好了。這樣是不會有什么問題的。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android基于AdapterViewFlipper實(shí)現(xiàn)的圖片/文字輪播動畫控件
這篇文章主要介紹了Android基于AdapterViewFlipper實(shí)現(xiàn)的圖片/文字輪播動畫控件,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下2021-04-04通過Android trace文件分析死鎖ANR實(shí)例過程
遇到ANR(Application Not Responding)是比較常見的問題,產(chǎn)生ANR的原因有很多,比如CPU使用過高、事件沒有得到及時的響應(yīng)、死鎖等,下面將通過一次因?yàn)樗梨i導(dǎo)致的ANR問題,來說明如何通過trace文件分析ANR問題2013-06-06android同時控制EditText輸入字符個數(shù)和禁止特殊字符輸入的方法
這篇文章主要介紹了android同時控制EditText輸入字符個數(shù)和禁止特殊字符輸入的方法,涉及Android操作EditText控制字符操作的技巧,需要的朋友可以參考下2015-04-04Android開發(fā)實(shí)現(xiàn)撥打電話與發(fā)送信息的方法分析
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)撥打電話與發(fā)送信息的方法,結(jié)合實(shí)例形式分析了Android撥打電話及發(fā)送信息相關(guān)布局、功能實(shí)現(xiàn)及權(quán)限控制操作技巧,需要的朋友可以參考下2017-12-12Android編程實(shí)現(xiàn)將ButtonBar放在屏幕底部的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)將ButtonBar放在屏幕底部的方法,涉及Android界面設(shè)計(jì)與文本操作相關(guān)技巧,需要的朋友可以參考下2017-03-03Android開發(fā)之圖形圖像與動畫(三)Animation效果的XML實(shí)現(xiàn)
使用XML來定義Tween Animation動畫的XML文件在工程中res/anim目錄,這個文件必須包含一個根元素,感興趣的友可以了解一下,希望本文對你有所幫助2013-01-01Android中利用matrix 控制圖片的旋轉(zhuǎn)、縮放、移動
本篇文章是對Android中利用matrix 控制圖片的旋轉(zhuǎn)、縮放、移動進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06