但如何在应用里自己实现?搜索过发现网上有如下的做法:
- Resources res = getResources();
- Configuration config = res.getConfiguration();
- config.locale = locale;
- DisplayMetrics dm = res.getDisplayMetrics();
- res.updateConfiguration(config, dm);
亲测,不成功。好吧,程序员又到了自力更生的时候了。下面开始讲应用多语言切换的三种方法。
先上效果图:
前两种方法的原理即在应用里实现“选择语言”。通过查看源码,其核心代码为:
- IActivityManager iActMag = ActivityManagerNative.getDefault();
- try {
- Configuration config = iActMag.getConfiguration();
- config.locale = locale;
- // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
- // 会重新调用 onCreate();
- iActMag.updateConfiguration(config);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- PS:感谢 曾阳 的帮助。
1. API欺骗
烧制到手机中的android.jar包含了Android所需的各种类与方法;而供开发者使用的android.jar只是其中的一部分。API欺骗是指在应用中去模拟未公开的类和方法让应用编译通过并生成APK,然而在应用实际运行中调用的却仍是烧制到手机中真实的android.jar。
通过核心代码可以看到我们要模拟的是ActivityManagerNative中的一个方法getDefault()和IActivityManager中的两个方法getConfiguration()与updateConfiguration(config)。参照源码,应用的工程结构图及代码模拟如下:
工程结构图:
代码:
- ActivityManagerNative.java
- package android.app;
- /**
- * @author Sodino E-mail:sodinoopen@hotmail.com
- * @version Time:2011-7-10 上午11:37:01
- */
- public abstract class ActivityManagerNative {
- public static IActivityManager getDefault() {
- return null;
- }
- }
- IActivityManager.java
- package android.app;
- import android.content.res.Configuration;
- import android.os.RemoteException;
- /**
- * @author Sodino E-mail:sodinoopen@hotmail.com
- * @version Time:2011-7-10 上午11:37:46
- */
- public abstract interface IActivityManager {
- public abstract Configuration getConfiguration() throws RemoteException;
- public abstract void updateConfiguration(Configuration paramConfiguration)
- throws RemoteException;
- }
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
直接上代码:
- private void updateLanguage(Locale locale) {
- Log.d("ANDROID_LAB", locale.toString());
- try {
- Object objIActMag, objActMagNative;
- Class clzIActMag = Class.forName("android.app.IActivityManager");
- Class clzActMagNative = Class.forName("android.app.ActivityManagerNative");
- Method mtdActMagNative$getDefault = clzActMagNative.getDeclaredMethod("getDefault");
- // IActivityManager iActMag = ActivityManagerNative.getDefault();
- objIActMag = mtdActMagNative$getDefault.invoke(clzActMagNative);
- // Configuration config = iActMag.getConfiguration();
- Method mtdIActMag$getConfiguration = clzIActMag.getDeclaredMethod("getConfiguration");
- Configuration config = (Configuration) mtdIActMag$getConfiguration.invoke(objIActMag);
- config.locale = locale;
- // iActMag.updateConfiguration(config);
- // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
- // 会重新调用 onCreate();
- Class[] clzParams = { Configuration.class };
- Method mtdIActMag$updateConfiguration = clzIActMag.getDeclaredMethod(
- "updateConfiguration", clzParams);
- mtdIActMag$updateConfiguration.invoke(objIActMag, config);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
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是这个的格式:
- <string name="app_name">语言应用</string>
- public static final class string {
- public static final int app_name=0x7f050001;
- }
3.1的问题就是如何实现id与string的匹配,解决方法为:
- Resources res = context.getResources();
- String pkg = context.getPackageName();
- String tag = "app_name";
- int idTag = res.getIdentifier(tag, "string", pkg);
这儿要用到一个新的工具了:XmlResourceParser,解析过程有点绕,但比SAX简单些。具体细节见LanguageApp_Sodino工程中的代码吧。
3.3 手动刷新界面。
要获取所有涉及到语系更新组件的索引逐一更新,体力活儿,细心点花点力气也可实现。
详细实现过程见下面三个工程中:
LanguageApp_APICheat
LanguageApp_Reflection
LanguageApp_Sodino
(PS:不要问我为什么下载的工程在IDE中为什么无法直接使用,为什么打开是乱码红叉一大堆,既然是程序员,遇到问题是不是也该自己多思考思考呢。)
注明出处:http://blog.csdn.net/sodino/article/details/6596709