前段時間公司 App 須要實現多語言切換功能,接到任務後先 Google 了下,發現搜到的方法都比較老舊,不少都莫名其妙,好比什麼 API 欺騙、反射、手動轉換語系,感受不該該這麼複雜地實現(也多是當時的環境下實現確實比較麻煩)。因此花了點時間研究了下,實現了應用內切換語言,且不是那麼複雜。html
和微信相似,在設置界面打開切換語言的界面,選擇語言後重啓 HomeActivity,語言切換完成,下次從新打開 App ,也是用戶設置的語言。android
1. 添加多語言文件git
在不一樣的 value 文件夾下(例如 value 、value-en、values-zh-rTW 文件夾)添加不一樣語言的 string.xml
文件,咱們的項目添加了英文、簡體中文、繁體中文三種語言,以下圖所示:github
其中英文須要翻譯,繁體若是沒有專門翻譯的話,能夠找個簡繁轉換網站,直接將簡體中文轉成繁體中文,我用的這個網站:在線中文簡體轉繁體。數據庫
2. 更新 Configuration 中的 locale 屬性微信
參照 Android 開發者官網 上的描述,Configuration 包含了設備的全部的配置信息,這些配置信息會影響應用獲取的資源。例如 string 資源,就是根據 Configuration 的 locale 屬性來判斷該取哪一種語言的 string 資源,默認是 value 文件夾下的。測試
主要代碼以下:網站
咱們用了 Locale
中的預設值 Locale.ENGLISH
、Locale.TRADITIONAL_CHINESE
和 Locale.SIMPLIFIED_CHINESE
,若是你須要設置的語言沒有預設值,你能夠本身新建一個 Locale
對象,具體自行 Google 吧。ui
注:跟隨系統設置是 Locale.getDefault()
spa
3. 重啓 HomeActivity
咱們的 App 有個啓動頁 WelcomeActivity,相似微信那個小人啓動頁,若是從歡迎頁重啓,並非一個好的體驗,應該和微信的語言設置同樣,直接回到 HomeActivity ,而不是從 WelcomeActivity 從新打開。實現其實也很簡單,代碼以下:
正常來講這段代碼應該是沒問題的,可是假如你的 App 存在某個 activity 和當前設置頁 activity 不在一個 task 棧內的話(好比你從某個通知頁用 FLAG_ACTIVITY_NEW_TASK
啓動的一個 activity),就不會應用語言設置。所以能夠直接殺掉當前 App 的進程,保證是「整個」重啓了:
按道理殺掉進程的兩行代碼任意一行便可,可是查閱相關資料,仍是兩個都加上吧,若是有詳細瞭解歡迎溝通。此段代碼其實參考自 CustomActivityOnCrash 開源項目,有興趣的能夠研究下這個開源庫捕捉崩潰信息,重啓應用部分的代碼。
4. 持久化存儲語言設置
按照上述三個步驟,你應該已經能夠看到了改變語言的效果了,可是當你殺掉應用,從新打開,發現設置又失效了。這是由於應用重啓後會讀取設備默認的 Configuration 信息,其中和語言相關的 locale 屬性也會變成默認值,也就是你在系統設置中選擇的語言。
當你的應用須要由用戶單獨設置語言,而不是僅僅跟隨系統語言,你就須要持久化存儲用戶的設置信息了。你能夠選擇數據庫、或 SharedPreferences 來存儲設置信息。
在應用啓動時須要讀取存儲的設置,並應用該配置,簡要代碼以下:
5. 改變系統設置的時候須要注意的問題
作完以上的步驟,我以爲應該是沒問題的了,可是事實證實我仍是圖樣。
在測試中我又發現了一個問題:當從應用中切出去,改變了系統語言的設置,當再切應用的時候,我發現語言也會變成系統語言(而我並沒在應用內設置跟隨系統)。
而後打斷點調試,發如今設備的配置信息(也就是 Configuration )發生變化時,會當即影響應用中的 Configuration 信息。
簡單來講,上一步中,咱們在 App 啓動時,讀取了用戶的設置信息,並應用到 Configuration 的 locale 屬性上,而後經過 resources.updateConfiguration(config, dm)
改變了應用的配置信息( Configuration )並生效,保證咱們的應用讀取的 string 資源都是用戶設置語言對應的資源。在咱們改變系統的語言以後,再回到咱們的應用中,此時的 Configuration 的 locale 屬性就會發生變化了,再也不是咱們剛纔本身的在應用啓動時設置的了,而是變成了系統的設置了。
解決辦法很簡單粗暴,在切回咱們的應用時,在顯示的 activity 的生命週期中作一些處理就行了,由於該 activity 多是應用中任一個,所以咱們在 BaseActivity
的 onCreate
中處理下(如評論中提到的,在改變了系統設置以後,回到應用會重走 activity 的 onCreate
,這個須要說明下)就行了:
這裏我就簡單說下思路,具體的代碼實現自行完成。建議將語言設置相關的代碼都封裝在一個 LanguageUtil
中,便於後期的維護。