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 по-другому или это просто системная ошибка?
- Я получаю java.lang.classnotfoundexception: com.mysql.jdbc.Driver
- Не удалось запустить sdkmanager --list (Android SDK) с Java 9
- Android - Как создать интерактивный список?
- Dx bad class file magic (cafebabe) или версия (0033.0000) с ADK14
- Какова максимальная глубина стека вызовов java?
PS Вот что я нашел. При первом запуске MainActivity (который после моего тура) Locale.getDefault()
верен, но ресурсы ошибочны. Но в других действиях это дает мне неправильную локаль и неправильные ресурсы из этой локали. После поворота экрана (или, возможно, другого изменения конфигурации) Locale.getDefault()
верен.
- Android AudioRecord class - быстро запускает живой микрофон, настраивает функцию обратного вызова
- Что такое JAVA_HOME? Как JVM находит путь javac, хранящийся в JAVA_HOME?
- Использование статических переменных в Android
- Завершение программы Java
- Как использовать WeakReference в разработке Java и Android?
- Как переместить / переименовать файл из внутреннего хранилища приложений во внешнее хранилище на Android?
- Как удалить материал, напечатанный на консоль System.out.println ()?
- Проблема при использовании пользовательского шрифта - «родной шрифт не может быть создан»
ОК. Наконец мне удалось найти решение.
Сначала вы должны знать, что в 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 }