Android N изменяет язык программным путем

Я нашел действительно странную ошибку, которая воспроизводится только на устройствах Android N.

В программе моего приложения есть возможность изменить язык. Вот код, который его изменяет.

public void update(Locale locale) { Locale.setDefault(locale); Configuration configuration = res.getConfiguration(); if (BuildUtils.isAtLeast24Api()) { LocaleList localeList = new LocaleList(locale); LocaleList.setDefault(localeList); configuration.setLocales(localeList); configuration.setLocale(locale); } else if (BuildUtils.isAtLeast17Api()){ configuration.setLocale(locale); } else { configuration.locale = locale; } res.updateConfiguration(configuration, res.getDisplayMetrics()); } 

Этот код отлично работает в действии моего тура (с вызовом recreate() ), но во всех последующих действиях все ресурсы String ошибочны. Вращение экрана исправляет его. Что я могу сделать с этой проблемой? Должен ли я менять локаль для Android N по-другому или это просто системная ошибка?

PS Вот что я нашел. При первом запуске MainActivity (который после моего тура) Locale.getDefault() верен, но ресурсы ошибочны. Но в других действиях это дает мне неправильную локаль и неправильные ресурсы из этой локали. После поворота экрана (или, возможно, другого изменения конфигурации) Locale.getDefault() верен.

ОК. Наконец мне удалось найти решение.

Сначала вы должны знать, что в 25 API Resources.updateConfiguration(...) устарел. Поэтому вместо этого вы можете сделать что-то вроде этого:

1) Вам нужно создать свой собственный ContextWrapper, который переопределит все параметры конфигурации в baseContext. Например, это мой ContextWrapper, который правильно меняет Locale. Обратите внимание на метод context.createConfigurationContext(configuration) .

 public class ContextWrapper extends android.content.ContextWrapper { public ContextWrapper(Context base) { super(base); } public static ContextWrapper wrap(Context context, Locale newLocale) { Resources res = context.getResources(); Configuration configuration = res.getConfiguration(); if (BuildUtils.isAtLeast24Api()) { configuration.setLocale(newLocale); LocaleList localeList = new LocaleList(newLocale); LocaleList.setDefault(localeList); configuration.setLocales(localeList); context = context.createConfigurationContext(configuration); } else if (BuildUtils.isAtLeast17Api()) { configuration.setLocale(newLocale); context = context.createConfigurationContext(configuration); } else { configuration.locale = newLocale; res.updateConfiguration(configuration, res.getDisplayMetrics()); } return new ContextWrapper(context); }} 

2) Вот что вы должны сделать в своей BaseActivity:

  @Override protected void attachBaseContext(Context newBase) { Locale newLocale; // .. create or get your new Locale object here. Context context = ContextWrapper.wrap(newBase, newLocale); super.attachBaseContext(context); } 

Заметка:

Не забудьте воссоздать свою деятельность, если вы хотите изменить Locale в своем приложении. Вы можете переопределить любую конфигурацию, в которой вы хотите использовать это решение.

Вдохновленный различными кодами (т. Е. Наши братья из Stackoverflow (выкрикивают мальчиков)), я выпустил гораздо более простую версию. Расширение ContextWrapper не нужно.

Сначала предположим, что у вас есть 2 кнопки для 2 языков, EN и KH. В onClick для кнопок сохранить код языка в SharedPreferences , а затем вызвать метод recreate() .

Пример:

 @Override public void onClick(View v) { switch(v.getId()) { case R.id.btn_lang_en: //save "en" to SharedPref here break; case R.id.btn_lang_kh: //save "kh" to SharedPref here break; default: break; } getActivity().recreate(); } 

Затем создайте статический метод, который возвращает ContextWrapper , возможно, в classе Utils (это то, что я сделал, lul).

 public static ContextWrapper changeLang(Context context, String lang_code){ Locale sysLocale; Resources rs = context.getResources(); Configuration config = rs.getConfiguration(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { sysLocale = config.getLocales().get(0); } else { sysLocale = config.locale; } if (!lang_code.equals("") && !sysLocale.getLanguage().equals(lang_code)) { Locale locale = new Locale(lang_code); Locale.setDefault(locale); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { config.setLocale(locale); } else { config.locale = locale; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { context = context.createConfigurationContext(config); } else { context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); } } return new ContextWrapper(context); } 

Наконец, загрузите код языка из SharedPreferences в attachBaseContext(Context newBase) ALL ACTIVITY .

 @Override protected void attachBaseContext(Context newBase) { String lang_code = "en"; //load it from SharedPref Context context = Utils.changeLang(newBase, lang_code); super.attachBaseContext(context); } 

БОНУС: Чтобы сохранить пот пальмы на клавиатуре, я создал class LangSupportBaseActivity который расширяет действие и использует последний fragment кода. И у меня есть все другие действия, расширяющие LangSupportBaseActivity .

Пример:

 public class LangSupportBaseActivity extends Activity{ ...blab blab blab so on and so forth lines of neccessary code @Override protected void attachBaseContext(Context newBase) { String lang_code = "en"; //load it from SharedPref Context context = Utils.changeLang(newBase, lang_code); super.attachBaseContext(context); } } public class HomeActivity extends LangSupportBaseActivity{ ...blab blab blab } 
  • Почему main () в java void?
  • как конвертировать миллисекунды в формат даты в android?
  • Как hash строку в Android?
  • Разрешение на запись на SD-карту
  • Почему вызовы метода интерфейса медленнее, чем конкретные вызовы?
  • Создание с помощью каталога Intellij 2017.2 / out дублирует файлы в каталоге / build
  • Как я могу представить диапазон в Java?
  • Проблемы с импортом проекта в Android Studio в отношении ActionBarSherlock
  • Как я могу изменить текст EditText без запуска Text Watcher?
  • java.lang.ClassNotFoundException: Не нашел class на пути: dexpathlist
  • Как сделать разделение 2 ints порождать float вместо другого int?
  • Interesting Posts

    Найти число десятичных знаков в десятичном значении независимо от культуры

    ggplot, объединяющий два графика из разных data.frames

    Как добавить уникальные JComboBoxes в столбец в JTable (Java)

    Переход в альбомный режим в Android Emulator

    «Переопределить метод суперclassа» Ошибки после импорта проекта в Eclipse

    ASP.NET перезапускается, когда папка создается, переименовывается или удаляется

    Может ли Grub быть настроен на запоминание последней загруженной ОС?

    Читайте url для строки в нескольких строках кода Java

    Структура Entity Framework и уровень изоляции транзакций

    Как ключевые слова IMMUTABLE, STABLE и VOLATILE влияют на поведение функции?

    Сервлеты для тестирования модhive

    Как ограничить ввод в EditText цифровым (возможно, десятичным и подписанным)?

    Можно ли определить «средний» диапазон в scale_fill_gradient2 ()?

    Может ли это быть хорошим подходом к обеспечению более безопасной защиты ОС от вредоносного ПО?

    C ++ 11 std :: mutex в тупике Visual Studio 2012 при блокировке из DllMain ()

    Давайте будем гением компьютера.