語言切換的三種方法

來源:互聯網
上載者:User

Android對國際化與多語言切換已經做得不錯了,一個應用只要命名相應語系的values-[language]檔案夾,通過“設定”→“語言&鍵盤”→“選擇語言”即可實現應用多種語言的切換。   

    但如何在應用裡自己實現?搜尋過發現網上有如下的做法:[java]
view plaincopy

  1. Resources res = getResources();  
  2. Configuration config = res.getConfiguration();  
  3. config.locale = locale;  
  4. DisplayMetrics dm = res.getDisplayMetrics();  
  5. res.updateConfiguration(config, dm);  

 
    親測,不成功。好吧,程式員又到了自力更生的時候了。下面開始講應用多語言切換的三種方法。
    
    先上:

 

前兩種方法的原理即在應用裡實現“選擇語言”。通過查看源碼,其核心代碼為:

[java]
view plaincopy
  1. IActivityManager iActMag = ActivityManagerNative.getDefault();  
  2. try {  
  3.     Configuration config = iActMag.getConfiguration();  
  4.     config.locale = locale;  
  5.     // 此處需要聲明許可權:android.permission.CHANGE_CONFIGURATION  
  6.     // 會重新調用 onCreate();  
  7.     iActMag.updateConfiguration(config);  
  8. } catch (RemoteException e) {  
  9.     e.printStackTrace();  
  10. }  
  11. PS:感謝 曾陽 的協助。  

    可以發現IActivityManager與ActivityManagerNative都是非公開類。如何調用?第一種是API欺騙,第二種是使用Java反射機制。
    1. API欺騙
    燒制到手機中的android.jar包含了Android所需的各種類與方法;而供開發人員使用的android.jar只是其中的一部分。API欺騙是指在應用中去類比未公開的類和方法讓應用編譯通過並產生APK,然而在應用實際運行中調用的卻仍是燒制到手機中真實的android.jar。
    
    通過核心代碼可以看到我們要類比的是ActivityManagerNative中的一個方法getDefault()和IActivityManager中的兩個方法getConfiguration()與updateConfiguration(config)。參照源碼,應用的工程結構圖及代碼類比如下:
    
    工程結構圖:

代碼:

[java]
view plaincopy
  1. ActivityManagerNative.java  
  2. package android.app;  
  3.   
  4. /** 
  5.  * @author Sodino E-mail:sodinoopen@hotmail.com 
  6.  * @version Time:2011-7-10 上午11:37:01 
  7.  */  
  8. public abstract class ActivityManagerNative {  
  9.     public static IActivityManager getDefault() {  
  10.         return null;  
  11.     }  
  12. }  
  13.   
  14. IActivityManager.java  
  15. package android.app;  
  16.   
  17. import android.content.res.Configuration;  
  18. import android.os.RemoteException;  
  19.   
  20. /** 
  21.  * @author Sodino E-mail:sodinoopen@hotmail.com 
  22.  * @version Time:2011-7-10 上午11:37:46 
  23.  */  
  24. public abstract interface IActivityManager {  
  25.     public abstract Configuration getConfiguration() throws RemoteException;  
  26.   
  27.     public abstract void updateConfiguration(Configuration paramConfiguration)  
  28.             throws RemoteException;  
  29. }  

    實現類比了這兩個類後,即可正常使用上面提到的轉換語系的核心代碼了。

    2. Java反射機制
    不多說了,Java反射機制入門教程:
    http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html
    之前寫過的幾個使用Java反射的例子:
    [Android]擷取未安裝的APK表徵圖(原創非轉帖)
    http://blog.csdn.net/sodino/article/details/6215224
    [Android]掛斷、電話中
    http://blog.csdn.net/sodino/article/details/6181610
    
    直接上代碼:

[java]
view plaincopy
  1. private void updateLanguage(Locale locale) {  
  2.     Log.d("ANDROID_LAB", locale.toString());  
  3.     try {  
  4.         Object objIActMag, objActMagNative;  
  5.         Class clzIActMag = Class.forName("android.app.IActivityManager");  
  6.         Class clzActMagNative = Class.forName("android.app.ActivityManagerNative");  
  7.         Method mtdActMagNative$getDefault = clzActMagNative.getDeclaredMethod("getDefault");  
  8.         // IActivityManager iActMag = ActivityManagerNative.getDefault();  
  9.         objIActMag = mtdActMagNative$getDefault.invoke(clzActMagNative);  
  10.         // Configuration config = iActMag.getConfiguration();  
  11.         Method mtdIActMag$getConfiguration = clzIActMag.getDeclaredMethod("getConfiguration");  
  12.         Configuration config = (Configuration) mtdIActMag$getConfiguration.invoke(objIActMag);  
  13.         config.locale = locale;  
  14.         // iActMag.updateConfiguration(config);  
  15.         // 此處需要聲明許可權:android.permission.CHANGE_CONFIGURATION  
  16.         // 會重新調用 onCreate();  
  17.         Class[] clzParams = { Configuration.class };  
  18.         Method mtdIActMag$updateConfiguration = clzIActMag.getDeclaredMethod(  
  19.                 "updateConfiguration", clzParams);  
  20.         mtdIActMag$updateConfiguration.invoke(objIActMag, config);  
  21.     } catch (Exception e) {  
  22.         e.printStackTrace();  
  23.     }  
  24. }  

    實際運行後,發現對當前系統設定了新的Locale後,不單自己的應用語系改變了,系統所有的應用語系都改變了。這肯定是不合理的。有一個解決辦法是在應用介面退出前再次對系統設定成碑的Locale,不過個人不喜歡這樣的辦法,加之調用updateConfiguration()方法後,整個Activity會重新onCreate(),這個考慮Activity的生命週期可有點費勁了。於是有了下面這第三種方法。
    
    3. 自己轉換語系(哈哈,這個名字很現實啊)
    動手實現嘛,啥都系統弄好了,那程式員的存在還有什麼意義呢。
    自己轉換語系有點麻煩,先看工程結構圖:
   

    values/strings.xml與xml/english.xml的內容是相同的;values-zh-rCN/strings.xml與xml/chinese.xml的內容也是相同的。出現這樣的冗餘是因為產生APK時values下的內容都打到rasc去了,讀取不了了。
    
    自己實現語系的轉換需要考慮到:
    3.1  R.xxxxx.id與對應語系中文本串的對應(需要特別考慮到R.array.string字串數組)。
    3.2 解析xml。
    3.3 設定語系後,所有介面元素的手動重新整理。
    
    在xml中聲明一個string是這個的格式:

[html]
view plaincopy
  1. <string name="app_name">語言應用</string>  

    對應R檔案會產生一個id指代該string[java]
view plaincopy

  1. public static final class string {  
  2.     public static final int app_name=0x7f050001;  
  3. }  

    3.1的問題就是如何?id與string的匹配,解決方案為:[java]
view plaincopy

  1. Resources res = context.getResources();  
  2. String pkg = context.getPackageName();  
  3. String tag = "app_name";  
  4. int idTag = res.getIdentifier(tag, "string", pkg);  

    3.2 解析XML
    這兒要用到一個新的工具了:XmlResourceParser,解析過程有點繞,但比SAX簡單些。具體細節見LanguageApp_Sodino工程中的代碼吧。
    
    3.3 手動重新整理介面。
    要擷取所有涉及到語系更新群組件的索引逐一更新,體力活兒,細心點花點力氣也可實現。
    
    詳細實現過程見下面三個工程中:
    LanguageApp_APICheat
    LanguageApp_Reflection
    LanguageApp_Sodino
    (PS:不要問我為什麼下載的工程在IDE中為什麼無法直接使用,為什麼開啟是亂碼紅叉一大堆,既然是程式員,遇到問題是不是也該自己多思考思考呢。)
本文內容歸CSDN部落格博主Sodino 所有

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.