android 应用内切换语言

一:创建不同语言的strings.xml

1.1 选中res,右键选择Android Resource Directory => Locale => >> 选择你需要的语言
1.2 将values下的strings.xml复制到对应语言下的values下
1.3 将不同strings.xml中的内容改成对应的语言文字,不同strings.xml中同一个内容的name是相同的
1.4 在布局文件或者代码中引用strings.xml里的内容
我选择了英文和繁体中文,创建好后如下图所示在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二:代码切换语言

android N以下,需要在application的onCreate里切换Locale,N及以上,在Activity的attachBaseContext去切换即可
实现代码如下

2.1 创建LocaleUtils文件

/**
     * 如果是7.0以下,我们需要调用changeAppLanguage方法,
     * 如果是7.0及以上系统,直接把我们想要切换的语言类型保存起来,在baseActivity中切换
     * 然后重新启动MainActivity
     * @param locale
     * @param context
     */
    public static void changeAppLanguage(Locale locale,Context context){
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        Configuration configuration = context.getResources().getConfiguration();
        if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.N)){
            configuration.setLocale(locale);
        }
        context.getResources().updateConfiguration(configuration,metrics);
        HawkUtil.INSTANCE.saveLocale(locale);
    }

    public static Context attachBaseContext(Context context){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context);
        }
        return context;
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context) {
        Locale locale = HawkUtil.INSTANCE.getLocale();
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLocales(new LocaleList(locale));
        return context.createConfigurationContext(configuration);
    }

2.2 自定义Application

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        Hawk.init(this).build()
        
        /**
         * 对于7.0以下,需要在Application创建的时候进行语言切换
         */
        val locale = HawkUtil.getLocale()
        LocaleUtils.changeAppLanguage(locale,this)
    }

    /**
     * 系统切换语言时,会回调次方法
     */
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        val locale = HawkUtil.getLocale()
        Locale.setDefault(locale)
        LocaleUtils.changeAppLanguage(locale,this)
    }
}

2.3 创建BaseActivity

open class BaseActivity : AppCompatActivity() {

    /**
     * 此方法先于 onCreate()方法执行
     * @param newBase
     */
    override fun attachBaseContext(newBase: Context?) {
        /**
         * attach对应语言环境下的context
         */
        super.attachBaseContext(LocaleUtils.attachBaseContext(newBase))
    }
}

2.4 将MainActivity继承BaseActivity

class MainActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<Button>(R.id.btn_simplified).setOnClickListener {
            switchAppLanguage(Locale.SIMPLIFIED_CHINESE)
        }
        findViewById<Button>(R.id.btn_traditional).setOnClickListener {
            switchAppLanguage(Locale.TRADITIONAL_CHINESE)
        }
        findViewById<Button>(R.id.btn_english).setOnClickListener {
            switchAppLanguage(Locale.US)
        }
    }

    private fun switchAppLanguage(locale: Locale){
        LocaleUtils.changeAppLanguage(locale,this)
        val intent = Intent(this, MainActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
        startActivity(intent)
    }
}

上面的代码代码只是可以切换语言,只适用于单页面,Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK会清掉任务栈里的activity实例,再将MainActivity的实例添加到新的任务栈。

在我实际的项目中,登录页面也可以进入到切换语言页面,而所有需要登录后才能操作的地方都可以进入到登录页,这样就需要保留任务栈。这时就不能直接用 2.4中switchAppLanguage()的方法了

在2.3中,在baseActivity中重写attachBaseContext(), 在切换语言后,已启动的activity会回调次方法。新启动的activity也会在onCreate()回调前先回调attachBaseContext(),所以需要考虑怎么让已有任务栈里的activity回调attachBaseContext()

我的做法是 自己维护一个任务栈,选择了相应的语言点击保存后。遍历自己维护的任务栈,调用activity的recreate()方法,代码如下

private fun finishPage(){
	//当前页面不recreate,不然会有闪退那样的闪一下
	AppManager.getInstance().activityStack.forEach {
		if (it !is SelectLanguageActivity){
			it.recreate()
		}
	}
	//别的activity recreate完,finish掉当前页面,返回到进入切换语言的页面
	finish()
}

注意,调用activity的recreate(),activity及view需要做好状态保存和恢复。

上面这样切换,在Android7的系统上会有问题
现在暂时的做法是在BaseActivity上重写getResources()方法
具体看如下代码

@Override
public Resources getResources() {
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < Build.VERSION_CODES.O){
		Context cc = LocaleUtil.INSTANCE.changeLang(getApplicationContext());
        return cc.getResources();
	}else {
    	return super.getResources();
	}
}

@Override
protected void attachBaseContext(Context newBase) {
	Context cc = LocaleUtil.INSTANCE.changeLang(newBase);
	super.attachBaseContext(cc);
}

LogcaleUtil.changeLang()的代码如下

fun changeLang(context: Context): Context{
	val res = context.resources
    val config = res.configuration
    val locale: Locale = HawkUtil.getLocale()
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
    	config.setLocale(locale)
        config.setLocales(LocaleList(locale))
	}else{
    	config.locale = locale
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
    	config.setLayoutDirection(locale)
        return ContextWrapper(context.createConfigurationContext(config))
    }else{
    	context.resources.updateConfiguration(config,res.displayMetrics)
        return ContextWrapper(context)
    }
}

打包aab发布到google play上,用户下载下来切换多语言可能会失败
设置多语言不分包处理可解决
在app级gradle中,Android-defuultConfig中添加如下代码

bundle {
	language {
		//多语言不分包处理
        enableSplit = false
	}
	density {
		// This property is set to true by default.
		enableSplit = true
	}
	abi {
		// This property is set to true by default.
		enableSplit = true
	}
}
  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值