Android-App内动态切换语言的坑(部分页面切换成功,部分页面切换失败。或者同一个页面出现多种语言的情况)

App内动态切换语言的坑

介绍

        本文介绍强制将App语言指定为中文。也就是不管当前系统是英文环境还是其他语言环境,都将App的语言指定为中文。简单直白废字数点,就是不管是什么语言环境,启动App看到都是中文。

备注:若需动态切换语言,原理和这个差不多。

代码

/**
 * @Creator City
 * @Date 2020/7/24
 * @Description:强制将App语言指定为中文
 * @params:activity,当前Activity
 * 忽略文中的try...catch...(项目即将上线时发现的问题,来不及测试,所以.....)
 */
fun forceChinese(activity: FragmentActivity) {
    fun action(res: Resources) {
        try {
            val config = res.configuration
            var local: Locale? = null
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            	// 可看Android手机设置->语言与输入法->语言。该页面是一个语言列表(localList)
            	// 就是代码这里的localList
                val localList = config.locales
                if (!localList.isEmpty) {
                	// 虽然localList是一个列表,但是生效的是第一个local,你调试一下就知道了
                    local = localList.get(0)
                }
            } else {
            	// 低版本sdk就只有一个local,没有语言列表
                local = config.locale
            }
            local?.let {
            	//中文环境(包括简体中文,繁体中文),若要指定地区,还要加上Locale.CHINESE.country
                val zh = Locale.CHINESE.language 
                if (!it.language.contains(zh)) {
                	// 打开注释,调试用,看看哪些页面会偷偷更改Local(可以打开一个内嵌WebView的Activity看看)
                	// Log.d("City_Language", res.toString())
                    config.setLocale(Locale.CHINESE)
                    // createConfigurationContext(config) // 推荐用该方法,但是不生效,原因未知
                    res.updateConfiguration(config, res.displayMetrics)
                }
            }
        } catch (e: Exception) {
            // empty
        }
    }
    try {
    	// ???为什么这里执行两次action
        action(BaseApplication.getApp().resources)
        action(activity.resources)
    } catch (e: Exception) {
        // empty
    }
}

使用

        我们一般在项目中有个Activity基类,我这里是BaseActivity。如果你项目里没有用到这样子的基类,建议你百度一下“Android BaseActivity”。
        备注:最近在学设计模式,这里的Activity基类也就是BaseActivity是“模板方法模式”哦。

/**
 * @Creator City
 * @Date 2020/7/26
 * @Description:
 * BaseLanguageActivity继承BaseActivity,具体Activity如PageActivity继承BaseLanguageActivity。
 * BaseLanguageActivity就只处理Language方面的,算不算六大原则之一的“单一职责原则”?
 */
abstract class BaseLanguageActivity : BaseActivity(){

	/**
	* 这个方法会在onCreate()之前调用
	* 为什么这里要调用?主要是第一个页面,后面的onResume,onConfiguration两个方法对于第一页不适用
	*/
    override fun attachBaseContext(newBase: Context?) {
        super.attachBaseContext(newBase)
        forceLanguage(this)
    }
    
	/**
	* 每次onResume都调用一次
	* 为什么?
	* 如果我们在PageA页面调用了一次,跳转到PageB页面更改了Local,那再次回到PageA页面时再调用一次,防止意外
	* 什么意外?实战来解释
	* 如果PageB页面内嵌了一个WebView。WebView内部会更改Local,这个是我猜的,我没看源码,当我打开PageB时
	* 发现方法forceChinese中的Log.d("City_Language", res.toString())有打印,说明我们在PageA页面更
	* 改为中文Local后,到PageB页面后Local发生了变化。
	*/
    override fun onResume() {
        super.onResume()
        forceLanguage(this)
    }

	/**
	* 系统的配置信息发生改变时,再调用一次forceLanguage
	*/
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        forceLanguage(this)
    }
}

多个Resource对象

        你是否发现你的App内部有多个Resource对象?我们先看看如何获取Resource对象:
1:getApplicationContext().getResources() // 在工具类中需要加载String时会采用ApplicationContext
2:getResources() // 在Activity里,直接获取
        当我们打印这两个Resource时,发现这两个地址并不同。因此一个App内有多少个Resource对象,并且在不同场景下要用到这些Resource时,就要分别设置Resource。像方法forceChinese()中那样。否则会出现“部分页面切换成功,部分页面切换失败。或者同一个页面出现多种语言的情况哦~~~”。

备注

        我是在模拟器Android 9、Android 10且是英文环境上进行调试的。
        如下图,localList,生效的是localList.get(0),也就是当前Phone语言环境是英文
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值