Я делал язык приложения доступным для пользователей. Итак, я добавил настройку языка в свое приложение. Я добавил счетчик на экран конфигурации, и у счетчика есть список языков (Авто, Английский sh, Китайский и др. c). Я сохраняю позицию выбранного элемента в общих настройках (значение по умолчанию 0, что Авто). В каждом классе деятельности я добавляю метод переопределения attachBaseContext (newBase: Context) . Этот код позволяет переопределить attachBaseContext
override fun attachBaseContext(newBase: Context) {
val shared = newBase.getSharedPreferences("configuration",Context.MODE_PRIVATE)
val position = shared?.getInt("Language",0) ?: 0
super.attachBaseContext(LocaleManager.langChange(newBase,position)
, и это LocaleManager
object LocaleManager {
fun langChange(context: Context, position: Int): ContextWrapper {
var lang: String = if(position < StaticStore.lang.size)
StaticStore.lang[position]
else
StaticStore.lang[0]
if(lang == "")
lang = Resources.getSystem().configuration.locales.get(0).language
val config = context.resources.configuration
if(lang != "") {
val loc = Locale(lang)
Locale.setDefault(loc)
config.setLocale(loc)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setSystemLocale(config,loc)
} else {
setSystemLocaleLegacy(config,loc)
}
}
var c = context
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
c = context.createConfigurationContext(config)
} else {
context.resources.updateConfiguration(config,context.resources.displayMetrics)
}
return ContextWrapper(c)
}
private fun setSystemLocaleLegacy(config: Configuration, loc: Locale) {
config.locale = loc
}
@TargetApi(Build.VERSION_CODES.N)
fun setSystemLocale(config: Configuration, loc: Locale) {
config.setLocale(loc)
}
}
StaticStore - это класс java, в котором хранятся переменные stati c. В StaticStore
public static String[] lang = {"","en","zh","ja"};
Этот способ работал нормально, когда я использовал Java. Я думал, что преобразование моего Android проекта в Kotlin будет хорошим, поэтому я сначала преобразовал классы деятельности. Но по какой-то причине этот способ сейчас не работает.
Я искал эту проблему часами. Пробовал эти ответы и не работал
{ ссылка } (Устанавливает локаль в классе, который расширяется Приложение )
{ ссылка } (Это похоже на мой код, но он использует LocaleList , а не Locale )
Но, к счастью, я попробовал этот способ, и он наконец заработал
override fun attachBaseContext(newBase: Context) {
val shared = newBase.getSharedPreferences(StaticStore.CONFIG, Context.MODE_PRIVATE)
val lang = shared?.getInt("Language",0) ?: 0
val config = Configuration() //Create new Configuration
var language = StaticStore.lang[lang]
if(language == "")
language = Resources.getSystem().configuration.locales.get(0).toString()
config.setLocale(Locale(language))
applyOverrideConfiguration(config) //Manually override configuration using "config"
super.attachBaseContext(LocaleManager.langChange(newBase,shared?.getInt("Language",0) ?: 0))
}
При открытии не выдает никаких ошибок, если указать c активность в первый раз . При повторном открытии того же действия (например, go возврат на главный экран и повторный вход на экран конфигурации) печатается ошибка
2020-01-26 11:26:55.619 28216-28216/com.mandarin.myapp E/AppCompatDelegate: updateForNightMode. Calling applyOverrideConfiguration() failed with an exception. Will fall back to using Resources.updateConfiguration()
java.lang.IllegalStateException: Override configuration has already been set
at android.view.ContextThemeWrapper.applyOverrideConfiguration(ContextThemeWrapper.java:99)
at androidx.appcompat.app.AppCompatDelegateImpl.updateForNightMode(AppCompatDelegateImpl.java:2281)
at androidx.appcompat.app.AppCompatDelegateImpl.applyDayNight(AppCompatDelegateImpl.java:2170)
at androidx.appcompat.app.AppCompatDelegateImpl.attachBaseContext(AppCompatDelegateImpl.java:334)
at androidx.appcompat.app.AppCompatActivity.attachBaseContext(AppCompatActivity.java:98)
at com.mandarin.myapp.ConfigScreen.attachBaseContext(ConfigScreen.kt:371)
at android.app.Activity.attach(Activity.java:6598)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2580)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Я понимаю эту ошибку, но мне приходится использовать applyOverrideConfiguration (config) для решения проблемы настройки локали. Странно то, что, хотя эта ошибка печатается, приложение не взломает sh, но меня это сильно беспокоит.
В любом случае, из-за этой ошибки я попытался использовать applyOverrideConfiguration (config) только один раз, используя stati c boolean. Это может изменить язык хорошо, когда я открываю деятельность в первый раз. Но когда я снова открываю ту же активность, она снова показывает язык по умолчанию (Engli sh - это язык устройства). Таким образом, это означает, что только applyOverrideConfiguration (config) может изменить язык ...
На самом деле мне не нужно вызывать этот метод, когда super.attachBaseContext (LocaleManager.langChange (newBase) , position) работает нормально, но по какой-то причине не работает.
Есть ли способы использовать applyOverrideConfiguration без ошибок печати? Или есть способы решить проблему изменения языка