Android多语言兼容N及以上(国际化)踩坑之旅

最近公司有了新需求,需要app支持多语言,这个任务分配到了我的头上,目前需要支持英文、中文简体和中文繁体,还有跟随系统语言。可是我没有做过国际化相关的需求,怎么办!当然是上网查了,Google或者百度都OK啦!废话不多说,下面开始进入正题啦

Android应用的资源文件国际化

在正式开始之前,先来讲解一下 Android 应用资源国际化的知识。对于资源文件的国际化,在默认的情况下,在 Android src/main/res/ 目录下会有一个默认的values,这个时候不管如何切换语言,应用显示的资源都不会发生任何改变的。比方说你把系统语言切换为英文,那些系统的软件会跟着变成英文,而你的软件却什么都没变,还是中文。这是为什么呢!因为默认只有一个values,不管你切换成什么语言,它在没有找到对应的values文件目录,就会只用默认的values了。那需要怎么做才行,很简单!建立对应语言文件夹,格式一般为:values-语言代号-地区代号,默认的资源是不包含语言代号和地区代号的。

就拿我需要支持英文、中文简体和中文繁体来说吧!因为我是需要支持这三种类型的语言,那我只需要建立中文简体(values-zh-rCN)和中文繁体(values-zh-rTW),并且在目录下建立strings文件,当然还需要在对应的strings中加入对应的语言文案。其它的语言都认为它是英文,使用默认的values就好了

默认的values:

简体中文values-zh-rCN:

繁体中文values-zh-rTW:

让大家看下效果吧!系统语言切换成简体中文、繁体中文和英文的状态

  

这样关于资源文件values就好了,但是这样就结束了吗?答案是否定的,我们作为一个合格的应用,怎么能让用户每次想切换语言的时候都去切换系统的语言,这样多麻烦呀!我们肯定需要在自己的应用中就支持的呀!

关于应用内多语言切换

先附上LanguageHelper完整代码,下面会为大家一一讲解

package com.example.jack.languagedemo

import android.content.Context
import android.content.SharedPreferences
import android.content.res.Resources
import android.os.Build
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.support.annotation.StringDef
import java.util.Locale

/**
 * Created by jack on 2018/9/15.
 * Copyright  2018 jack.huang@dadaabc.com. All rights reserved.
 */
object LanguageHelper {

    @StringDef(SYSTEM, SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE, ENGLISH)
    @Retention(AnnotationRetention.SOURCE)
    annotation class LanguageStatus

    const val SYSTEM = "system"
    const val SIMPLIFIED_CHINESE = "zh_CN"
    const val TRADITIONAL_CHINESE = "zh_TW"
    const val ENGLISH = "en_US"

    private val SIMPLIFIED_CHINESE_TYPE: Locale = Locale.SIMPLIFIED_CHINESE
    private val TRADITIONAL_CHINESE_TYPE: Locale = Locale.TRADITIONAL_CHINESE
    private val ENGLISH_TYPE: Locale = Locale.ENGLISH

    private const val CHINESE = "zh"
    private const val SIMPLIFIED = "CN"
    private const val TRADITIONAL = "TW"

    private val languagePreference = LanguagePreference(CommonHelper.context)

    var languageStatus: String? = null
        get() {
            if (field == null) {
                val languageStatus = languagePreference.getLanguageStatus()
                field = if (languageStatus.isNotEmpty()) {
                    languageStatus
                } else {
                    SYSTEM
                }
            }
            return field
        }

    fun switchLanguage(context: Context, @LanguageStatus language: String): Context {
        saveLanguageStatus(language)
        return when (language) {
            SYSTEM -> languageCompat(context, systemLanguage())
            SIMPLIFIED_CHINESE -> languageCompat(context, SIMPLIFIED_CHINESE_TYPE)
            TRADITIONAL_CHINESE -> languageCompat(context, TRADITIONAL_CHINESE_TYPE)
            ENGLISH -> languageCompat(context, ENGLISH_TYPE)
            else -> context
        }
    }

    private fun languageCompat(context: Context, locale: Locale): Context {
        val resources = context.resources ?: return context
        val config = resources.configuration ?: return context
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            config.setLocale(locale)
        } else {
            @Suppress("DEPRECATION")
            config.locale = locale
        }
        if (VERSION.SDK_INT >= VERSION_CODES.N) {
            return context.createConfigurationContext(config)
        } else {
            val dm = resources.displayMetrics ?: return context
            @Suppress("DEPRECATION")
            resources.updateConfiguration(config, dm)
            return context
        }
    }

    private fun saveLanguageStatus(@LanguageStatus languageStatus: String) {
        LanguageHelper.languageStatus = languageStatus
        languagePreference.setLanguageStatus(languageStatus)
    }

    fun getLanguageType(): String {
        var languageType = languageStatus.toString()
        if (languageStatus == SYSTEM) {
            val systemLanguage = systemLanguage().language
            val systemCountry = systemLanguage().country
            if (systemLanguage == CHINESE) {
                if (systemCountry == SIMPLIFIED) {
                    languageType = SIMPLIFIED_CHINESE
                } else if (systemCountry == TRADITIONAL) {
                    languageType = TRADITIONAL_CHINESE
                }
            } else {
                languageType = ENGLISH
            }
        }
        return languageType
    }

    private fun systemLanguage(): Locale {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 解决了获取系统默认错误的问题
            Resources.getSystem().configuration.locales.get(0)
        } else {
            Locale.getDefault()
        }
    }

    fun isChineseLanguage(): Boolean {
        return getLanguageType() != ENGLISH
    }

    fun getLocal(): Locale {
        return when (LanguageHelper.getLanguageType()) {
            this.SIMPLIFIED_CHINESE -> SIMPLIFIED_CHINESE_TYPE
            this.TRADITIONAL_CHINESE -> TRADITIONAL_CHINESE_TYPE
            else -> ENGLISH_TYPE
        }
    }

    private class LanguagePreference(context: Context) {

        private val sharedPreferences: SharedPreferences by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            context.applicationContext.getSharedPreferences("languagePreference", Context.MODE_PRIVATE)
        }

        private val languageStatus = "language_status"

        fun setLanguageStatus(languageStatus: String) {
            setString(this.languageStatus, languageStatus)
        }

        fun getLanguageStatus(): String {
            return getString(this.languageStatus)
        }

        fun setString(keyName: String, value: String) {
            val editor = sharedPreferences.edit()
            editor.putString(keyName, value)
            editor.apply()
        }

        fun getString(keyName: String): String {
            val sp = sharedPreferences
            return sp.getString(keyName, "")
        }
    }
}


获取系统默认的语言和地区

只需要调用Android原生的API获取到应用内的语言,并且设置成我们想要的语言就好了,需要注意一下的事兼容性问题,Android >= Build.VERSION_CODES.JELLY_BEAN_MR1 用的是config.setLocale(locale),否则用的是config.locale = locale。Android >= Build.VERSION_CODES.N 用的是context.createConfigurationContext(config),它会重新创建一个context,val dm = resources.displayMetrics ?: return context  resources.updateConfiguration(config, dm) 则还是原先的context

    private fun languageCompat(context: Context, locale: Locale): Context {
        val resources = context.resources ?: return context
        val config = resources.configuration ?: return context
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            config.setLocale(locale)
        } else {
            @Suppress("DEPRECATION")
            config.locale = locale
        }
        if (VERSION.SDK_INT >= VERSION_CODES.N) {
            return context.createConfigurationContext(config)
        } else {
            val dm = resources.displayMetrics ?: return context
            @Suppress("DEPRECATION")
            resources.updateConfiguration(config, dm)
            return context
        }
    }

定义切换状态和语言类型

根据我目前的需求,需要有四种状态:跟随系统、简体中文、繁体中文、英文这些状态,但是语言类型只有三种呀!分别是简体中文、繁体中文、英文这些语言类型,所以还需要把跟随系统的状态转为简体中文、繁体中文、英文的类型。然后就可以切换对应的语言了,再加上本地数据持久化。这边值得一提的是,获取系统默认语言在>=N的版本的情况下Locale.getDefault(),它是获取到你上次设置的应用内语言,不是我们想要的系统语言,需要使用Resources.getSystem().configuration.locales.get(0)才行,这是踩坑踩出来

    @StringDef(SYSTEM, SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE, ENGLISH)
    @Retention(AnnotationRetention.SOURCE)
    annotation class LanguageStatus

    const val SYSTEM = "system"
    const val SIMPLIFIED_CHINESE = "zh_CN"
    const val TRADITIONAL_CHINESE = "zh_TW"
    const val ENGLISH = "en_US"

    private val SIMPLIFIED_CHINESE_TYPE: Locale = Locale.SIMPLIFIED_CHINESE
    private val TRADITIONAL_CHINESE_TYPE: Locale = Locale.TRADITIONAL_CHINESE
    private val ENGLISH_TYPE: Locale = Locale.ENGLISH

    private val languagePreference = LanguagePreference(CommonHelper.context)

    var languageStatus: String? = null
        get() {
            if (field == null) {
                val languageStatus = languagePreference.getLanguageStatus()
                field = if (languageStatus.isNotEmpty()) {
                    languageStatus
                } else {
                    SYSTEM
                }
            }
            return field
        }

    fun switchLanguage(context: Context, @LanguageStatus language: String): Context {
        saveLanguageStatus(language)
        return when (language) {
            SYSTEM -> languageCompat(context, systemLanguage())
            SIMPLIFIED_CHINESE -> languageCompat(context, SIMPLIFIED_CHINESE_TYPE)
            TRADITIONAL_CHINESE -> languageCompat(context, TRADITIONAL_CHINESE_TYPE)
            ENGLISH -> languageCompat(context, ENGLISH_TYPE)
            else -> context
        }
    }

    private fun systemLanguage(): Locale {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 解决了获取系统默认错误的问题
            Resources.getSystem().configuration.locales.get(0)
        } else {
            Locale.getDefault()
        }
    }

    private class LanguagePreference(context: Context) {

        private val sharedPreferences: SharedPreferences by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            context.applicationContext.getSharedPreferences("languagePreference", Context.MODE_PRIVATE)
        }

        private val languageStatus = "language_status"

        fun setLanguageStatus(languageStatus: String) {
            setString(this.languageStatus, languageStatus)
        }

        fun getLanguageStatus(): String {
            return getString(this.languageStatus)
        }

        fun setString(keyName: String, value: String) {
            val editor = sharedPreferences.edit()
            editor.putString(keyName, value)
            editor.apply()
        }

        fun getString(keyName: String): String {
            val sp = sharedPreferences
            return sp.getString(keyName, "")
        }
    }

当前的语言类型和当前的Local以及是否是中文语言  

        根据产品需要我需要将当前切换成什么语言告诉接口和网页,需要提供出当前的语言类型。当前项目还有带有时间的自定义控件,需要提供出是否中英文的判断。以及系统的一些时间,需要根据不同的Local,展示出对应的时间格式

    private const val CHINESE = "zh"
    private const val SIMPLIFIED = "CN"
    private const val TRADITIONAL = "TW"

    fun getLanguageType(): String {
        var languageType = languageStatus.toString()
        if (languageStatus == SYSTEM) {
            val systemLanguage = systemLanguage().language
            val systemCountry = systemLanguage().country
            if (systemLanguage == CHINESE) {
                if (systemCountry == SIMPLIFIED) {
                    languageType = SIMPLIFIED_CHINESE
                } else if (systemCountry == TRADITIONAL) {
                    languageType = TRADITIONAL_CHINESE
                }
            } else {
                languageType = ENGLISH
            }
        }
        return languageType
    }

    fun isChineseLanguage(): Boolean {
        return getLanguageType() != ENGLISH
    }

    fun getLocal(): Locale {
        return when (LanguageHelper.getLanguageType()) {
            this.SIMPLIFIED_CHINESE -> SIMPLIFIED_CHINESE_TYPE
            this.TRADITIONAL_CHINESE -> TRADITIONAL_CHINESE_TYPE
            else -> ENGLISH_TYPE
        }
    }

多语言切换踩坑继续

LanguageActivity

先附上完整代码:

package com.example.jack.languagedemo

import android.content.Intent
import android.os.Bundle
import android.view.View
import com.example.jack.languagedemo.LanguageHelper.LanguageStatus
import kotlinx.android.synthetic.main.activity_language.englishIcon
import kotlinx.android.synthetic.main.activity_language.englishLayout
import kotlinx.android.synthetic.main.activity_language.simplifiedChineseIcon
import kotlinx.android.synthetic.main.activity_language.simplifiedChineseLayout
import kotlinx.android.synthetic.main.activity_language.tracingSystemIcon
import kotlinx.android.synthetic.main.activity_language.tracingSystemLayout
import kotlinx.android.synthetic.main.activity_language.traditionalChineseIcon
import kotlinx.android.synthetic.main.activity_language.traditionalChineseLayout

/**
 * Created by jack on 2018/9/15.
 * Copyright  2018 jack.huang@dadaabc.com. All rights reserved.
 */
class LanguageActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_language)
        initStatus()
        initView()
    }

    private fun initStatus() {
        when (LanguageHelper.languageStatus) {
            LanguageHelper.SYSTEM -> systemStatus()
            LanguageHelper.SIMPLIFIED_CHINESE -> simplifiedChineseStatus()
            LanguageHelper.TRADITIONAL_CHINESE -> traditionalChineseStatus()
            LanguageHelper.ENGLISH -> englishStatus()
            else -> systemStatus()
        }
    }

    private fun initView() {
        tracingSystemLayout.setOnClickListener {
            systemStatus()
            switchLanguage(LanguageHelper.SYSTEM)
        }
        simplifiedChineseLayout.setOnClickListener {
            simplifiedChineseStatus()
            switchLanguage(LanguageHelper.SIMPLIFIED_CHINESE)
        }
        traditionalChineseLayout.setOnClickListener {
            traditionalChineseStatus()
            switchLanguage(LanguageHelper.TRADITIONAL_CHINESE)
        }
        englishLayout.setOnClickListener {
            englishStatus()
            switchLanguage(LanguageHelper.ENGLISH)
        }
    }

    private fun systemStatus() {
        tracingSystemIcon.visibility = View.VISIBLE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.GONE
    }

    private fun simplifiedChineseStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.VISIBLE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.GONE
    }

    private fun traditionalChineseStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.VISIBLE
        englishIcon.visibility = View.GONE
    }

    private fun englishStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.VISIBLE
    }

    private fun switchLanguage(@LanguageStatus languageStatus: String) {
        if (LanguageHelper.languageStatus == languageStatus) return
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
        startActivity(intent)
        finish()
    }
}

首先一进来需要获取到当前处于什么状态,根据状态展示UI效果

    private fun initStatus() {
        when (LanguageHelper.languageStatus) {
            LanguageHelper.SYSTEM -> systemStatus()
            LanguageHelper.SIMPLIFIED_CHINESE -> simplifiedChineseStatus()
            LanguageHelper.TRADITIONAL_CHINESE -> traditionalChineseStatus()
            LanguageHelper.ENGLISH -> englishStatus()
            else -> systemStatus()
        }
    }

    private fun systemStatus() {
        tracingSystemIcon.visibility = View.VISIBLE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.GONE
    }

    private fun simplifiedChineseStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.VISIBLE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.GONE
    }

    private fun traditionalChineseStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.VISIBLE
        englishIcon.visibility = View.GONE
    }

    private fun englishStatus() {
        tracingSystemIcon.visibility = View.GONE
        simplifiedChineseIcon.visibility = View.GONE
        traditionalChineseIcon.visibility = View.GONE
        englishIcon.visibility = View.VISIBLE
    }

然后就是切语言啦,想切哪个切哪个,切完之后把所有栈退掉,关闭当前页面,跳转至MainActivty。为什么要这样做,我不会关闭当前页面,不退栈不行吗?一会你就知道了

    private fun initView() {
        tracingSystemLayout.setOnClickListener {
            systemStatus()
            switchLanguage(LanguageHelper.SYSTEM)
        }
        simplifiedChineseLayout.setOnClickListener {
            simplifiedChineseStatus()
            switchLanguage(LanguageHelper.SIMPLIFIED_CHINESE)
        }
        traditionalChineseLayout.setOnClickListener {
            traditionalChineseStatus()
            switchLanguage(LanguageHelper.TRADITIONAL_CHINESE)
        }
        englishLayout.setOnClickListener {
            englishStatus()
            switchLanguage(LanguageHelper.ENGLISH)
        }
    }

    private fun switchLanguage(@LanguageStatus languageStatus: String) {
        if (LanguageHelper.languageStatus == languageStatus) return
        CommonHelper.context = LanguageHelper.switchLanguage(CommonHelper.context, languageStatus)
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
        startActivity(intent)
        finish()
    }

BaseActivity

这样就完了吗?答案是否定的,我们最重要的地方来了。思考一下,我们为什么可以实现多语言切换?前面说了根据系统切换语言是在Android src/main/res/ 的下建立对应的values,这样就能找到对应的strings文件,从而相匹配对应。不管是AndroidManifest还是布局文件都是.xml的格式,最终都会转化成java或kotlin代码,在java或kotlin代码中是怎样拿到string的呢!getString()拿到的对吧,而getString()又依赖于Context。关键点就在Context,先说说系统默认实现吧!当你切换系统语言的时候,系统会拿到你切换的语言和Context相关联(具体怎么实现自己看源码吧),这样Context里面的getString()就可以找到对应的values从而拿到对应的strings展示了。好吧!前面做了这么多,就是为了拿到一个带有语言信息的Context,所以我们只需要把这个Context替换掉原先的Context就好了。建立一个BaseActivity,让所有Activity继承它,重写attachBaseContext(),替换掉原来的Context。说到这里应该知道为什么切换完语言之后要退栈关闭本页面了吧!因为attachBaseContext()只有在第一次进入的时候才会执行

    override fun attachBaseContext(newBase: Context) {
        val context = LanguageHelper.languageStatus?.let { languageStatus ->
            LanguageHelper.switchLanguage(newBase, languageStatus)
        }
        super.attachBaseContext(context)
    }

看看效果吧!

不知道大家有没有发现,主界面和多语言(ActionBar)一直都是简体中文,并没有根据切换语言而改变,正常来说是不会的呀!哈哈,我是在AndroidManiest中设置ActionBar-title

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.jack.languagedemo">

    <application
        android:name=".AppApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:label="@string/main_title">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".LanguageActivity"
            android:label="@string/language_title"/>
    </application>

</manifest>

为什么会这样呢!好像是因为AndroidManifest只会执行一次吧!切换语言的时候,它不知道呀!那我就想再在这设置便于统一管理,不想在代码中设置怎么办?它不是只会执行一次不是,那我就让它执行多次好了,在BaseActivity中重写onCreate(),动态的去获取在AndroidManiest中设置的label,然后设置给ActionBar,toolbar同理!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        title = getLabel()
    }

    private fun getLabel(): String? {
        var label: String? = null
        try {
            val activityInfo = packageManager.getActivityInfo(componentName, 0) ?: return null
            label = if (activityInfo.labelRes != 0) {
                getString(activityInfo.labelRes)
            } else {
                activityInfo.nonLocalizedLabel as String?
            }
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return label
    }

看看效果如何:

这样Activty级别的多语言切换就OK了

Application级别的多语言切换

一般来说,项目中都会有Application的Context,我这个是不是不生效呀!那我们就试一试

package com.example.jack.languagedemo

import android.app.Application
import android.content.Context

/**
 * Created by jack on 2018/9/15.
 * Copyright  2018 jack.huang@dadaabc.com. All rights reserved.
 */
class AppApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        CommonHelper.context = this
    }

}

package com.example.jack.languagedemo

import android.annotation.SuppressLint
import android.content.Context

/**
 * Created by jack on 2018/9/15.
 * Copyright  2018 jack.huang@dadaabc.com. All rights reserved.
 */
@SuppressLint("StaticFieldLeak")
object CommonHelper {
    /**
     * Application context.
     */
    lateinit var context: Context
}
package com.example.jack.languagedemo

import android.content.Intent
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.beautifulTextView
import kotlinx.android.synthetic.main.activity_main.mainLanguage

class MainActivity : BaseActivity() {

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

    private fun initView() {
        beautifulTextView.text = CommonHelper.context.getString(R.string.beautiful)
        mainLanguage.setOnClickListener({
            startActivity(Intent(this@MainActivity, LanguageActivity::class.java))
        })
    }
}

看看效果:

今天天气不错啊!这段文字一直都是简体,并没有跟随语言切换。所以还需要对Application的Context进行处理,可是之前Activtiy切换完要退栈,那我Application切换完岂不是需要重启应用了,不好不好。还好Application的Context是全局独有而一直存在的,就不用考虑内存泄漏的问题了,我只要把带语言信息的Context保存下来,用的时候直接用这个就好了。修改两处地方,初始化和切换语言的时候

Application这边需要注意的是需要重写attachBaseContext(),因为LanguageHelper.languageStatus用到了s p,它是需要Context的,所以需要先取一下Context

package com.example.jack.languagedemo

import android.app.Application
import android.content.Context

/**
 * Created by jack on 2018/9/15.
 * Copyright  2018 jack.huang@dadaabc.com. All rights reserved.
 */
class AppApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        LanguageHelper.languageStatus?.let { languageStatus ->
            CommonHelper.context = LanguageHelper.switchLanguage(this, languageStatus)
        }
    }

    override fun attachBaseContext(base: Context) {
        CommonHelper.context = base
        super.attachBaseContext(base)
    }

}

LanguageActivity这边需要注意的是不能给LanguageHelper.switchLanguage()传入Activity的Context,需要传入CommHelper的Context,不然Activity的Context就被静态引用了,N以下的设备就会引起内存泄漏了,大于等于N的是重新创建的Context,所以不会

   private fun switchLanguage(@LanguageStatus languageStatus: String) {
        if (LanguageHelper.languageStatus == languageStatus) return
        CommonHelper.context = LanguageHelper.switchLanguage(CommonHelper.context, languageStatus)
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
        startActivity(intent)
        finish()
    }

看看效果:

好了,多语言切换就到此结束了        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值