Изменение языка не работает после перехода на Androidx

У меня есть старый проект, который поддерживает несколько языков. Я хочу обновить библиотеку поддержки и целевую платформу. До перехода на Androidx все работало нормально, но теперь смена языка не работает!

Я использую этот код для изменения локали приложения по умолчанию

private static Context updateResources(Context context, String language)
{
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);

    return context.createConfigurationContext(configuration);
}

И вызывайте этот метод для каждого действия путем переопределения attachBaseContext следующим образом:

@Override
protected void attachBaseContext(Context newBase)
{
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    String language = preferences.getString(SELECTED_LANGUAGE, "fa");
    super.attachBaseContext(updateResources(newBase, language));
}

Я стараюсь другой метод, чтобы получить строку, и я заметил, что getActivity().getBaseContext().getString работы и getActivity().getString не работает. Даже следующий код не работает и всегда показывает app_name vlaue в ресурсе по умолчанию string.xml.

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"/>

Я поделился примером кода в https://github.com/Freydoonk/LanguageTest

Также getActivity()..getResources().getIdentifier не работает и всегда возвращает 0!

Ответ 1

Наконец я нахожу проблему в своем приложении. При переносе проекта на Androidx зависимости моего проекта менялись так:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.1.0-alpha04'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha02'
} 

Как видно, версия androidx.appcompat:appcompat 1.1.0-alpha03 когда я изменил ее на последнюю стабильную версию 1.0.2, моя проблема решена и язык изменения работает должным образом.

Я нахожу последнюю стабильную версию библиотеки appcompat в репозитории Maven. Я также изменяю другие библиотеки на последнюю стабильную версию.

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

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.0.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

Ответ 2

В основном, что происходит в фоновом режиме, это то, что, если вы правильно установили конфигурацию в attachBaseContext, AppCompatDelegateImpl затем переходит и переопределяет конфигурацию в совершенно новую конфигурацию без локали:

 final Configuration conf = new Configuration();
 conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);

 try {
     ...
     ((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
     handled = true;
 } catch (IllegalStateException e) {
     ...
 }

В последнем (пока не выпущенном) коде это на самом деле исправлено: новая конфигурация является глубокой копией конфигурации базового контекста.

final Configuration conf = new Configuration(baseConfiguration);
conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
try {
    ...
    ((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
    handled = true;
} catch (IllegalStateException e) {
    ...
}

Пока это не будет выпущено, то же самое можно сделать вручную. Чтобы продолжить использовать версию 1.1.0, добавьте это ниже вашего attachBaseContext:

Раствор Котлина

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
    if (overrideConfiguration != null) {
        val uiMode = overrideConfiguration.uiMode
        overrideConfiguration.setTo(baseContext.resources.configuration)
        overrideConfiguration.uiMode = uiMode
    }
    super.applyOverrideConfiguration(overrideConfiguration)
}

Java-решение

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
    if (overrideConfiguration != null) {
        int uiMode = overrideConfiguration.uiMode;
        overrideConfiguration.setTo(getBaseContext().getResources().getConfiguration());
        overrideConfiguration.uiMode = uiMode;
    }
    super.applyOverrideConfiguration(overrideConfiguration);
}

Этот код делает то же самое, что Configuration(baseConfiguration) делает под капотом, но поскольку мы делаем это после того, как AppCompatDelegate уже установил правильный uiMode, мы должны убедиться, что переопределяем uiMode после того, как мы это исправим, чтобы не потерять настройку темного/светлого режима.

Ответ 3

В новых библиотеках приложений, связанных с ночным режимом, существует проблема, которая приводит к переопределению конфигурации на Android с 21 по 25. Это можно исправить, применив вашу конфигурацию при вызове этой общедоступной функции:

public void applyOverrideConfiguration (Конфигурация overrideConfiguration

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

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
if (Build.VERSION.SDK_INT >= 21&& Build.VERSION.SDK_INT <= 25) {
        getResources().getConfiguration().setTo(overrideConfiguration);
    }
super.applyOverrideConfiguration(getResources().getConfiguration());
}

Ответ 4

Теперь есть более новая версия, которая также работает:

implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'

Как @Fred упомянул appcompat:1.1.0-alpha03 имеет сбой, хотя он не упоминается в журнале их appcompat:1.1.0-alpha03 версий

Ответ 5

Наконец, я получил решение для поиска, в моем случае проблема была с bundle apk, потому что он разделил файлы поиска. В bundle apk по умолчанию будут созданы все сплиты. но в блоке android вашего файла build.gradle вы можете указать, какие разделы будут сгенерированы.

bundle {
            language {
                // Specifies that the app bundle should not support
                // configuration APKs for language resources. These
                // resources are instead packaged with each base and
                // dynamic feature APK.
                enableSplit = false
            }
        }

После добавления этого кода в блок android файла build.gradle моя проблема была решена.

Ответ 6

Была такая же ошибка на androidx.appcompat:appcompat:1.1.0. Переключился на androidx.appcompat:appcompat:1.1.0-rc01 и теперь меняются langs на Android 5-6.

Ответ 7

1. Метод, который вы можете использовать в attachBaseContext()

private void setLanguage(Context mContext, String localeName) {
        Locale myLocale = new Locale(localeName);
        Resources res = mContext.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        Configuration conf = res.getConfiguration();
        conf.locale = myLocale;
        res.updateConfiguration(conf, dm);
    }

2. Переопределить в деятельности

@Override
protected void attachBaseContext(Context newBase) {
    setLanguage(newBase, "your language");
    super.attachBaseContext(newBase);
}

NB: Это нормально работает после того, как я воссоздаю упражнение