Android之动态设置App语言环境

来源:互联网 发布:淘宝怎样推广宝贝 编辑:程序博客网 时间:2024/04/28 08:07

首先,为什么会写这篇文章呢?那就是今天端午节,苦日子终于熬出头了,app版本正式交付。O(∩_∩)O哈哈~

进入正题,开发过程中需要动态改变app的语言环境,这个时候就需要用到Android自带的Locale类。也许会说,app的语言的环境不是系统自动寻找values-的文件吗?要知道,这只是系统根据自带语言设置应用资源的搜索策略,即values- → valuse的搜索顺序。但是,要考虑到有时候应用的语言环境要区别于系统语言环境,这个时候,代码中动态改变app语言环境就很有必要。

直接上代码:

 /**     * 切换应用语言环境     *     * @param context     */    private void loadAppLanguage(Context context, Locale targtLocal) {        //todo 模拟器无法跟随指定语言环境        if (context == null) {            throw new NullPointerException("loadAppLanguage failed because context is null");        }        lg.e("loadAppLanguage:" + targtLocal);        Configuration config = context.getResources().getConfiguration();        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {            config.setLocale(targtLocal);        } else {            //noinspection deprecation            config.locale = targtLocal;        }        context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());        Locale.setDefault(targtLocal);    }

so 简单,有木有~~

好,扔给妹子测试去,我先喝杯吃个水果拼盘先。话说,公司福利还是不错的哈~
然后,~~~咦,怎么屏幕旋转的时候都变成中文了?还有,系统切换语言成繁文的时候,app怎么也跟着变了?
翻阅相关资料后,发现屏幕旋转时或者系统语言变更后都需要重新设置。好,上代码:

//注册语言变更监听器        context.registerReceiver(new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                lg.e("监听到语言变化");                loadAppLanguage(context, locale);            }        }, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));

关于监听屏幕旋转切换时的监听操作,网上多半是直接重写Activity的onConfigurationChanged方式,但说实话,这种方法弊端很明显,如果是老旧代码遗留的历史债务,改起来就相当恶心。而且我很讨厌到处改代码,信奉的原则是怎么偷懒怎么来。(Application也可以在onConfigurationChanged设置 - 用了,接下来还怎么装*?O(∩_∩)O~ 其实在后面会说明,一个单独的模块,最好不要让开发人员做太多的控制,模块内部把所有的工作都做完最好!)
仔细想想,为什么不直接Hook系统的状态切换呢?分析下,我们只要拿到UI进程的状态通信类,就可以做自己的工作了。Hook UI线程的原理这里就按下不表了,感兴趣的自己去网上查资料,代码贴在下面。

    /**     * 监听主线程的Handler对象     */    public static void hookActivityThreadHandler(Handler.Callback callback) {        if (callback == null) {            lg.e("not support hookActivityThreadHandler because Handler.Callback not define");            return;        }        try {            //由于ActivityThread无法直接访问            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");            Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");            currentActivityThreadMethod.setAccessible(true);            //获取主线程对象            Object activityThreadObj = currentActivityThreadMethod.invoke(null);            //获取mH字段q            Field mH = activityThreadClass.getDeclaredField("mH");            mH.setAccessible(true);            //获取Handler            Handler handler = (Handler) mH.get(activityThreadObj);            //获取原始的mCallBack字段            Field mCallBack = Handler.class.getDeclaredField("mCallback");            mCallBack.setAccessible(true);            //这里设置自定义实现的CallBack接口对象            mCallBack.set(handler, callback);        } catch (Exception e) {            e.printStackTrace();        }    }

好了,入口代码如下,

public void setAppLocale(final Context context, final Locale locale) {        //避免多进程重复调用        if (!TempUtils.isUIPid(context)) {            return;        }        loadAppLanguage(context, locale);        //注册语言变更监听器        context.registerReceiver(new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                lg.e("监听到语言变化");                loadAppLanguage(context, locale);            }        }, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));        //监听横竖屏切换        HookUtils.hookActivityThreadHandler(new Handler.Callback() {            @Override            public boolean handleMessage(Message msg) {                //118:@link ActivityThread - CONFIGURATION_CHANGED                if (msg.what == 118) {                    if (msg.obj instanceof Configuration) {                        lg.e("检测到屏幕旋转,重置app语言环境");                        loadAppLanguage(context, locale);                    }                }                return false;            }        });    }

只需要在Application的入口地方直接调用

new LanguageManager().setAppLocale(this,Locale.ENGLISH);

,剩下的所有工作全部自动帮你管理。

小Tips:
1.其实动态设置语言这个东西可以用的很活。比如现在需要把页面布局改下样式然后快速上线,但是又不想对原有的布局以及资源文件进行改动,这个时候完全可以自定义莫须有的语言环境,然后。。。你懂得!!!

原创粉丝点击