Android对国际化与多语言切换已经做得不错了,一个应用只要命名相应语系的values-[language]文件夹,通过“设置”→“语言&键盘”→“选择语言”即可实现应用多种语言的切换。    
 
   但如何在应用里自己实现?搜索过发现网上有如下的做法:
 
1. res = getResources();  
2. config = res.getConfiguration();  
3. = locale;  
4. dm = res.getDisplayMetrics();  
5. dm);
 
  
 
   亲测,不成功。好吧,程序员又到了自力更生的时候了。下面开始讲应用多语言切换的三种方法。
 
   
 
   先上效果图:
 
 
![English [Android]应用语言切换的三种方法_android](https://file.cfanz.cn/uploads/gif/2022/01/16/14/XV476I6FI5.gif)
  
![[Android]应用语言切换的三种方法_java_02](https://file.cfanz.cn/uploads/gif/2022/01/16/14/XV476I6FI5.gif)
前两种方法的原理即在应用里实现“选择语言”。通过查看源码,其核心代码为:
  
1. 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. 曾阳 的帮助。
    
 
   1. API欺骗 
   烧制到手机中的android.jar包含了Android所需的各种类与方法;而供开发者使用的android.jar只是其中的一部分。API欺骗是指在应用中去模拟未公开的类和方法让应用编译通过并生成APK,然而在应用实际运行中调用的却仍是烧制到手机中真实的android.jar。 
   通过核心代码可以看到我们要模拟的是ActivityManagerNative中的一个方法getDefault()和IActivityManager中的两个方法getConfiguration()与updateConfiguration(config)。参照源码,应用的工程结构图及代码模拟如下: 
   工程结构图:  
 
![[Android]应用语言切换的三种方法_java_02](https://file.cfanz.cn/uploads/gif/2022/01/16/14/XV476I6FI5.gif)
代码:
  
1.  
2.  packageandroid.app;  
3.  
4.  
5.  publicabstractclassActivityManagerNative {  
6.    publicstaticIActivityManager getDefault() {  
7.        returnnull;  
8.    }  
9.  
10.  
11.  
12.  packageandroid.app;  
13.  
14.  importandroid.content.res.Configuration;  
15.  importandroid.os.RemoteException;  
16.  
17.  
18.  publicabstractinterfaceIActivityManager {  
19.    publicabstractConfiguration getConfiguration() throwsRemoteException;  
20.  
21.    publicabstractvoidupdateConfiguration(Configuration paramConfiguration)  
22.            throwsRemoteException;  
23.
   2. Java反射机制
     不多说了,Java反射机制入门教程:
     http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html     之前写过的几个使用Java反射的例子:
     [Android]获取未安装的APK图标(原创非转帖)
 
     
     直接上代码:
  
   
   
1.  privatevoidupdateLanguage(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. 
    
   3. 自己转换语系(哈哈,这个名字很现实啊) 
   动手实现嘛,啥都系统弄好了,那程序员的存在还有什么意义呢。 
   自己转换语系有点麻烦,先看工程结构图: 
![[Android]应用语言切换的三种方法_java_02](https://file.cfanz.cn/uploads/gif/2022/01/16/14/XV476I6FI5.gif)
    
 
     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是这个的格式:
  
   
1. stringname="app_name">语言应用</</span>string>    
 
1.  publicstaticfinalclassstring {  
2.    publicstaticfinalintapp_name=0x7f050001;  
3.  
   3.1的问题就是如何实现id与string的匹配,解决方法为: 
1. res = context.getResources();  
2. pkg = context.getPackageName();  
3. tag = "app_name";  
4.  intidTag = res.getIdentifier(tag, "string", pkg); 
   这儿要用到一个新的工具了:XmlResourceParser,解析过程有点绕,但比SAX简单些。具体细节见LanguageApp_Sodino工程中的代码吧。 
    
   3.3 手动刷新界面。 
   要获取所有涉及到语系更新组件的索引逐一更新,体力活儿,细心点花点力气也可实现。 
    
   详细实现过程见下面三个工程中: 
LanguageApp_APICheat
LanguageApp_Reflection
LanguageApp_Sodino










