Android 应用程序上下文配置不会使用新的语言环境进行更新

Zba*_*ian 15 android locale

当我不在保留所有业务逻辑的自定义构建类中使用Context相关类(活动、片段、服务、视图等)时,我需要访问应用程序的本地化字符串ViewModel。例如,在 a的帮助下将 a发布String到:UILiveData

toastMessageLiveData.value = buildLastLoginToastMessage()

fun buildLastLoginToastMessage() {
   val lastLoginDiff = (System.currentMillis() - getLastLogin()) / DateUtils.HOURS_IN_MILLIS

   return MyApp.instance.getString(R.string.last_login_txt, lastLoginDiff)
}
Run Code Online (Sandbox Code Playgroud)

现在,Activity我正在观察LiveData的变化,并显示 Toast 消息。

这工作正常,但如果用户更改应用程序的语言就会出现问题。布局已更新,我可以看到使用了新语言环境的语言,但该MyApp.instance.getString(R.string....)功能仍在使用旧语言环境。如果我强制终止应用程序并重新启动它,它会工作,因为attachBaseContext再次调用应用程序并应用新的语言环境。但是,我不想强​​制终止应用程序,我需要一个解决方案来更新应用程序的配置。

用于创建或更新 Context

fun buildLocalizedContext(context: Context): Context {
   // From preferences, load the saved Language and Country codes
   val language = getSavedLanguage()
   val country = getSavedCountry()

   // Create the new locale
   val locale = Locale(language, country)
   Locale.setDefault(locale)

   val resources = context.resources
   val configuration = Configuration(resources.configuration)

   // Create a new configration or update the existing one if the API is less than 17
   if (Build.VERSION.SDK_INT >= 17) {
      configuration.setLocale(locale)
      return context.createConfigurationContext(configuration)
   } else {
      configuration.locale = locale
      resources.updateConfiguration(configuration, resources.getDisplayMetrics())
   }

   return context
}
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时,应用新的语言环境

class MyApp: Application {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(LocaleHelper.instance.buildLocalizedContext(base))
    }
}
Run Code Online (Sandbox Code Playgroud)

BaseActivity其他活动正在使用的类:

class BaseActivity: AppCompatActivity {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(LocaleHelper.instance.buildLocalizedContext(newBase))
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,这是我设法做到的,但这也不起作用:

fun changeLocale(locale: Locale, app: Application) {
    Locale.setDefault(locale)

    val resources = app.resources
    val configuration = resources.configuration

    if (Build.VERSION.SDK_INT >= 17) {
        configuration.setLocale(locale)
    }
    else {
        configuration.locale = locale
        resources.updateConfiguration(configuration, resources.displayMetrics)
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码片段不起作用,它不会更改应用程序的区域设置,仅当我强制重新启动应用程序时。

小智 2

正如您所经历的,语言和其他一些配置仅应用于视图上下文,而不是应用程序上下文。你的处境似乎很奇怪。您可能需要重新审视您的架构。通常,您希望获取视图中的字符串并将其传递给 ViewModel 进行处理。但是,如果您想让它按原样工作,也许您可​​以将 WeakReference 存储到应用程序对象内的视图,并使用它来获取本地化字符串。您还可以保留对视图的硬引用,但是您必须确保清除它以避免内存泄漏。最好的解决方案是修改您的架构,但这也是一个不错的解决方案。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        (application as App).activity = WeakReference<Activity>(this)
        }
}

class App : Application {
var activity : WeakReference<Activity>? = null
}
Run Code Online (Sandbox Code Playgroud)