? ? 前陣子因?yàn)楣境鴩H市場的進(jìn)軍,上面要求做起多語言的切換(目前只要求中英雙語),其中踩了不少的坑要销,來這邊簡單歸納一下构回。根據(jù)往常,我把本章節(jié)進(jìn)行一下目錄整理如下:
? ? 1疏咐、系統(tǒng)設(shè)置中Android 7.0 前后語言設(shè)置的區(qū)別與準(zhǔn)備工作
????2纤掸、Application與Activity兩種配置修改方式
? ? 3、具體的實(shí)現(xiàn)
? ? 4浑塞、踩的坑
? ? 目前能想到的就這么幾個借跪,現(xiàn)在我們進(jìn)入正文。
1酌壕、系統(tǒng)設(shè)置中Android 7.0 前后語言設(shè)置的區(qū)別與準(zhǔn)備工作
? ? 我們先從系統(tǒng)設(shè)置來查看一下掏愁,語言切換的變化
? ? 可知,在7.0之前仅孩,是直接把你手機(jī)的語言庫列表進(jìn)行展示托猩,然后在列表中進(jìn)行選擇。而7.0及其之后則是通過進(jìn)行添加把語言庫加載進(jìn)來辽慕,而加載進(jìn)來的一般的第一的就相當(dāng)于是你的母語(譬如中文)京腥,第二的相當(dāng)于是你的第二語言(譬如英文)。顯示的也是根據(jù)第一條對應(yīng)的語言庫進(jìn)行語言庫填充溅蛉。
? ? 準(zhǔn)備工作大致可分為以下幾個步驟:
? ? 1公浪、添加多語言文件:在不同的 value 文件夾下(例如 value 他宛、value-en、values-zh-rTW 文件夾)添加不同語言的?string.xml?文件欠气。根據(jù)我的項(xiàng)目需求厅各,目前只需要中英,所以對應(yīng)目錄建設(shè)如下预柒,如果需要其他語言队塘,你可以自己進(jìn)行創(chuàng)建。
????2宜鸯、文件屬性配置:的在AndroidManifest.xml里面進(jìn)行配置憔古,加上該權(quán)限
???<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
????允許一個程序修改當(dāng)前設(shè)置,如本地化(Allowsan application to modify the current configuration, such as locale. )
? ? 如果采用Activity的策略淋袖,則需要在AndroidManifest.xml文件里的每一個Activity進(jìn)行配置鸿市,這個在下文會詳細(xì)說。
? ??3即碗、代碼里的基本邏輯:這里就很籠統(tǒng)焰情,一般是選擇的機(jī)制和其他輔助工具的前期準(zhǔn)備。比如我是通過SharePreference進(jìn)行記錄用戶選擇之類的剥懒。我個人是認(rèn)為這屬于準(zhǔn)備工作内舟,所以在這邊說明一下。
2初橘、Application與Activity兩種配置修改方式
? ? 總的來說谒获,我們多語言的切換大多都是基于value文件夾下的string文件進(jìn)行配置和獲取。這就引伸到壁却,我們獲取這個資源的context是屬于Activity還是Application了批狱。這里我們先說一下,實(shí)現(xiàn)的步驟:
????1展东、Application方式
? ? 這種方式配置簡單赔硫,因?yàn)橐粋€app只有一個application,我們針對的目標(biāo)也就只有這么一個類盐肃,而且避免了一些情況下爪膊,某些activity的特殊情況造成不統(tǒng)一。當(dāng)然砸王,采取這種方式會帶來一些問題推盛,在我遇到的這些問題中,對應(yīng)的針對方法也有(可能不夠優(yōu)美谦铃,或者更好的方法我沒發(fā)現(xiàn))耘成。這里我把大致步驟說一下,比較重要的代碼進(jìn)行張貼,詳細(xì)的步驟可以去搜索網(wǎng)上的瘪菌。
? ? 先在application類中重寫配置修改回調(diào)方法如下:
????@Override
????public void onConfigurationChanged(Configuration newConfig) {
????????ContextWrapper warp = LanUtils.wrap(this, LanUtils.getTargetLable());
????????super.onConfigurationChanged(warp.getApplicationContext().getResources().getConfiguration());
}
????上面對應(yīng)的方法在這里面撒会,而LanUtils.getTargetLable()則是我記錄的,已經(jīng)切換的locale的記錄對象师妙,這個小伙伴們可以自行實(shí)現(xiàn)诵肛。下述方法因?yàn)檫€有其他地方用得到,所以我進(jìn)行封裝
? ? 當(dāng)然默穴,在application類的onCreat方法也需要進(jìn)行初始化怔檩,本人采取的是這種方法。因?yàn)檫€有一個跟隨系統(tǒng)的選項(xiàng)蓄诽,因此在每次app啟動創(chuàng)建的時候進(jìn)行語言選擇一次珠洗。至此,當(dāng)你把工具類實(shí)現(xiàn)了若专,就可以實(shí)現(xiàn)多語言切換了,但是這只能修改以application對應(yīng)的context進(jìn)行資源索引的更新蝴猪,而布局里的采取的還是以activity调衰,這時候你需要去你的baseActivity里重寫該方法:
????@Override
????protected void attachBaseContext(Context newBase) {
????????Context context = LanUtils.wrap(newBase, LanUtils.getTargetLable());
????????super.attachBaseContext(context);
????}
????這樣在每次activity獲取基本上下文的時候,才能將activity的context進(jìn)行配置更新自阱。當(dāng)然嚎莉,這種方式需要reCreate對應(yīng)的已存在的activity才能夠較好地實(shí)現(xiàn)目標(biāo)狀態(tài)。
????2沛豌、Activity方式
? ? 這個方式最大的優(yōu)點(diǎn)就是可以不進(jìn)行activity的重建趋箩,而且實(shí)現(xiàn)也很簡單,但是隱患也相對多加派。這里我們先介紹一個屬性:
????Configuration?這個類描述了設(shè)備的所有配置信息叫确,這些配置信息會影響到應(yīng)用程序檢索的資源。包括了用戶指定的選項(xiàng)(locale和scaling)也包括設(shè)備本身配置(例如input modes芍锦,screen size ?and ?screen orientation).可以在該類里查看所有影響Configuration Change 的屬性竹勉。
????橫豎屏切換是我們最常見的影響配置變化的因素,還有很多其他影響配置的因素有語言的更改(例如中英文切換)娄琉、鍵盤的可用性(這個沒理解)等
????常見的引發(fā)Configuration Change的屬性:
????橫豎屏切換:android:configChanges="orientation"
????鍵盤可用性:android:configChanges="keyboardHidden"
????屏幕大小變化:android:configChanges="screenSize"
????語言的更改:android:configChanges="locale"
????在程序運(yùn)行時次乓,如果發(fā)生Configuration Change會導(dǎo)致當(dāng)前的Activity被銷毀并重新創(chuàng)建,即先調(diào)用onDestroy緊接著調(diào)用onCreate()方法孽水。重建的目的是為了讓應(yīng)用程序通過自動加載可替代資源來適應(yīng)新的配置票腰。
? ? 當(dāng)我們沒有配置的時候,上述的變化都會造成activity的重建女气。因此我們在每個activity都需要補(bǔ)上對應(yīng)屬性杏慰,如:
????android:configChanges="orientation|screenSize|locale"?
????配置完后,我們在activity就不需要重建(對應(yīng)是否會重建需要針對具體屬性和場景,請自行搜索其他情況逃默,這里不詳細(xì)說明)鹃愤,只走對應(yīng)回調(diào)方法即可(同理,可針對橫豎屏切換等的場景)
? ? 同樣完域,在這種方式下就可以在語言切換的時候软吐,傳遞activity的上下文context進(jìn)行多語言配置更新。
? ? 3吟税、兩種方式的優(yōu)缺點(diǎn)
? ? 從上頭我們可以知道凹耙,application方式,目標(biāo)單一肠仪,比較不會造成混亂肖抱,而且在AndroidManifest.xml配置文件也是比較清晰的。而activity方式异旧,則是無需重建activity意述,而且配置步驟十分簡單。然而二者的缺點(diǎn)也是不可忽視的:
? ? application:
????需要重建activity吮蛹,造成損耗荤崇;
????當(dāng)你生命周期管理不夠好的時候,很容易在切換語言造成異常(當(dāng)然這個不是它的鍋潮针,說明你自己生命周期管理不善)术荤;
? ? 當(dāng)橫豎屏切換、webview相關(guān)問題的時候也會出現(xiàn)語言設(shè)置失效每篷。
? ? activity:
????AndroidManifest.xml里需要對每個activity進(jìn)行相關(guān)屬性配置瓣戚,使得結(jié)構(gòu)遠(yuǎn)不如上一個清晰;
? ? Google官方并不推薦為了某單一配置變化而阻止重建進(jìn)行自我配置,理由有幾個焦读,有網(wǎng)友簡單歸納幾點(diǎn):
????1.??配置改變和資源調(diào)整的問題子库,因?yàn)橛眠@個方法我們需要自己往onConfigurationChanged()里寫代碼,保證所用資源和設(shè)備的 當(dāng)前配置一致矗晃,如果一個馬虎程序很容易出現(xiàn)資源指定的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沒法阻止應(yīng)用重啟。(是說的有些android:configChanges的屬性值對避免重建無效喧兄?不知道理解是否正確)
????3.?很多開發(fā)人員會錯誤指定android:configChanges="orientation"來防止activity被銷毀或重建這種不可預(yù)知的情況无畔。但是引起Configuration Changes的情況很多,不止是屏幕旋轉(zhuǎn)吠冤。比如修改設(shè)備默認(rèn)語言浑彰,修改設(shè)備默認(rèn)字體比例等等都可會引起配置改變。這種方法只對當(dāng)前設(shè)置的配置有效拯辙,除非在manifest里把所有配置都列全郭变。
????4.?當(dāng)用戶離開應(yīng)用颜价,在回到應(yīng)用前被銷毀的話,例如點(diǎn)擊了屏幕的Home鍵或者有個電話打進(jìn)來诉濒,用戶很久之后才回到應(yīng)用程序周伦,但是在此之前系統(tǒng)因?yàn)橘Y源緊張而銷毀了應(yīng)用進(jìn)程,當(dāng)用戶返回還是要重新創(chuàng)建activity未荒,問題等于沒解決专挪。
? ? 綜上,取用哪種方法可以根據(jù)你的需求所決定片排。
3寨腔、具體的實(shí)現(xiàn)
? ? 上文已經(jīng)說了實(shí)現(xiàn)方式的不同與各自的方法,自然也需要對應(yīng)的實(shí)現(xiàn)方式率寡。先說明以下迫卢,由于本人的app主活動需要一直存在,所以一開始設(shè)計的時候主活動的默認(rèn)運(yùn)行與界面復(fù)雜度都盡量降低冶共,因此重建的成本比較低乾蛤,采用了第一種方法,對應(yīng)的工具類多少也有點(diǎn)定制化了捅僵。
? ? 首先家卖,在application里onCreat進(jìn)行初始化:? ??
? ? ? ? 在我們每次進(jìn)行語言選擇的時候,就需要對本地的配置進(jìn)行語言選擇更新命咐,其中以7.0 為分界線,7.0之前與7.0+是存在差別的:
? ? 而跟隨系統(tǒng)的時候谐岁,就需要進(jìn)行設(shè)置監(jiān)聽:
????????<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)) {
????????????????//如果是跟隨系統(tǒng)醋奠,則進(jìn)行應(yīng)用重啟
? ? ? ? ? ? String userSelectLanguage = LocalModel.getLanguageSelect();
????????????if (LanUtils.DefaultLanguage.equals(userSelectLanguage)) {
????????????????exit...
? ? ? ? ? }else {
????????????LanUtils.languageSelect(userSelectLanguage,true);}}}
????}
? ? 對應(yīng)的邏輯可以自行完善
4、踩的坑
????第1個是橫豎屏切換伊佃,造成了多語言設(shè)置的失效
????由于項(xiàng)目采用了公司的前輩自己封裝的框架窜司,造成application類被其隱藏,只有對應(yīng)主要生命周期回調(diào)方法航揉,造成application的onConfigurationChanged無法重寫塞祈,所以在橫豎屏切換的時候發(fā)生該問題。
? ? 解決的方法很粗暴帅涂,由于就是在activity的每次onCreat的時候進(jìn)行context的語言與目標(biāo)語言是否一致议薪,如果一致就不操作,不一致就進(jìn)行語言選擇操作媳友。
?? ??第2個是WebView斯议,造成了多語言設(shè)置的失效
? ? 根據(jù)網(wǎng)上搜索,該問題是發(fā)生在Android N之后的版本醇锚,原因就是:
????webview 在Android N之后哼御,webview的相關(guān)類以及相關(guān)jar的修改
????Android N 之前:
? ? Android的WebView是使用webkit構(gòu)建的坯临。雖然它最初是AOSP的一部分,但是從KitKat開始恋昼,決定分離出WebView一個名為Android System WebView的組件看靠。它基本上是一個Android系統(tǒng)應(yīng)用程序,預(yù)裝了Android設(shè)備液肌。它會像其他系統(tǒng)應(yīng)用程序(如Google Play服務(wù)和Play商店應(yīng)用程序)一樣定期更新挟炬。您可以在已安裝的系統(tǒng)應(yīng)用列表中看到它:
????Android 7.0之后:
? ? Chrome應(yīng)用將用于呈現(xiàn)WebView第三方Android應(yīng)用中的任何/所有內(nèi)容。在具有Android N開箱即用的手機(jī)中矩屁,Android WebView系統(tǒng)應(yīng)用
????解決方法:
? ? 1辟宗、在對應(yīng)的application的onCreat里補(bǔ)充上:new WebView(this).destroy();? ??
????2、在所有Activity下重設(shè)語言吝秕。StackOverFlow的回答中說也可以只在含有WebView的Activity中重設(shè)泊脐。這里建議,還是全設(shè)置掉好一點(diǎn)烁峭。在你的BaseActivity中容客,并且在調(diào)用setContentView之前調(diào)用如下代碼設(shè)置你的Local。
? ? 不過本人切換語言有走activity重建约郁,所以缩挑,并沒有在每個activity進(jìn)行重設(shè)置。而是在對應(yīng)activity的初始化(onCreat)進(jìn)行語言判斷與設(shè)置鬓梅。為了在其前后創(chuàng)建的活動同樣進(jìn)行語言判斷與設(shè)置供置。
? ? 到這里,大致就把多語言設(shè)置進(jìn)行簡單的說明绽快。主要的步驟很簡單芥丧,但是里面的坑不少,本人遇到了相當(dāng)一部分坊罢,但是應(yīng)該還沒完全遇到续担,結(jié)合其他博客所闡述的情況,在這里進(jìn)行一些歸納與總結(jié)活孩,作為自己的筆記也希望能給你們提供參考物遇,如有疏漏或者錯誤,希望不吝指正憾儒,萬分感激??
? ? 注:本人所寫的工具類在如下網(wǎng)盤询兴,沒有完全獨(dú)立,簡單修改一下應(yīng)該是適用的起趾,希望能夠幫到你
? ? 鏈接:百度網(wǎng)盤共享地址? 密碼:d9nr
參考博文:
---------------------
作者:?回歸的阿廖? 來源:CSDN? ?題目:Android Configuration change引發(fā)的問題及解決方法
鏈接:https://blog.csdn.net/aliaooooo/article/details/23606179
---------------------
作者:拜天地??來源:CSDN? 題目:【安卓學(xué)習(xí)之常見問題】 多國語言橫豎屏?xí)r蕉朵,自動切換到默認(rèn)語言(android:configChanges的使用)
鏈接:https://blog.csdn.net/ljb568838953/article/details/77005347
---------------------
作者:火鳳燎原??來源:CSDN? ?題目:Android7(N)中webview導(dǎo)致應(yīng)用內(nèi)語言切換失效
鏈接:https://blog.csdn.net/ArimaKisho/article/details/79798752