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 } 
  • javax.mail.AuthenticationFailedException выбрасывается при отправке электронной почты в java
  • Как использовать UTF-8 в свойствах ресурсов с помощью ResourceBundle
  • SSLHandshakeException Цепочный якорь для пути сертификации не найден Android HTTPS
  • Получение программной версии ОС на Android программно
  • Что такое sharedUserId в Android и как оно используется?
  • ArrayList не обновляется внутри функции onChildAdded
  • Запуск действий на вкладке в Android
  • Как получить текущее местоположение в Android
  • Как конвертировать 24-х часовой формат в формат до 12 часов?
  • Как получить список установленных принтеров?
  • Код будет возвращать 0.0, 0.0 GPS-координату при бросании NullPointerException
  • Давайте будем гением компьютера.