Изменение локали во время выполнения не влияет на фрагменты

#android #android-layout #android-fragments #locale

#Android #android-макет #android-фрагменты #язык

Вопрос:

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

Я тестировал это в nougat, marshmallow и oreo, и это происходит во всех ОС.

Когда пользователь меняет язык, я выполняю следующее.

  LocaleHelper.setLocale(getApplicationContext(), language);
 recreate();
  

LocalHelper

 public static Context setLocale(Context context, String language) {
        persist(context, language);


        Log.d("LocaleSet", language);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }

        return updateResourcesLegacy(context, language);
    }
  

Метод для post marshmallow OS.

    @TargetApi(Build.VERSION_CODES.N)
    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);
    }
  

Предварительная нуга

 @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }

        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return context;
    }
  

В каждом действии я выполняю следующий код.

 @Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(LocaleHelper.onAttach(base, LocaleHelper.getLanguage(base)));
}
  

Mainfest

 <application
        android:name=".GlobalApplication"
        android:allowBackup="false"
        android:icon="@mipmap/app_icon"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/app_icon"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:windowSoftInputMode="adjustPan"
        tools:replace="android:allowBackup">

        <activity
            android:name=".activities.homeactivity.HomeActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:configChanges="locale"
            android:theme="@style/AppTheme.NoActionBar" />

        <activity
            android:name=".activities.profilepageactivity.ProfilePageActivity"
            android:label="@string/title_activity_profile_page"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar" />
  

Комментарии:

1. Можете ли вы также добавить свой AndroidManifest.xml ?

2. @madlymad: я обновил вопрос и добавил файл манифеста, пожалуйста, проверьте.

3. Вы пробовали это без указания android:configChanges="locale" в манифесте?

4. Это может быть связано с тем, как вы форматируете свои даты

5. Большое спасибо, я использовал новый SimpleDateFormat(DatePattern, new Locale(«язык»)) , и теперь его дата загрузки в порядке.. Пожалуйста, добавьте свое решение в качестве ответа, я приму его. не могли бы вы также указать мне, как android:configChanges это исправить.

Ответ №1:

Я предполагаю, что вы используете этот подход. Там, где не предложено никаких изменений в AndroidManifest.xml so android:configChanges="locale" , это может привести к неправильному поведению, которое вы определили.

Для форматирования даты вы должны учитывать, что ваше приложение не использует Locale.getDefault() , а что-то другое, что определяется пользователем и вашим LocaleHelper механизмом.

Некоторые дополнительные сведения об изменении конфигурации

Это android:configChanges означает, что вы не хотите, чтобы система воссоздавала вашу активность при возникновении одного из предоставленных атрибутов. В вашем случае locale .

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

 @Override
public void onConfigurationChanged(Configuration newConfig) {
  // refresh your views here
  super.onConfigurationChanged(newConfig);
}
  

а затем выполните свою собственную обработку. То, что вам не требовалось в вашем случае.

Ответ №2:

Класс приложения, который расширен в файле манифеста.

 package com.example.languageapplication;

import android.content.Context;

public class Application extends android.app.Application {

    private static Application applicationInstance;

    public static synchronized Application getInstance() {
        return applicationInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        applicationInstance = this;
    }

    public void initAppLanguage(Context context) {
        LocaleUtils.initialize(context, LocaleUtils.getSelectedLanguageId());
    }

}
  

Locale использует класс для заданного языка в общих настройках и обновляет конфигурацию для заданного языка

 public class LocaleUtils {

    public static final String ENGLISH = "en";
    public static final String FRENCH = "fr";
    public static final String SPANISH = "es";


    public static void initialize(Context context, @LocaleDef String defaultLanguage) {
        setLocale(context, defaultLanguage);
    }

    public static boolean setLocale(Context context, @LocaleDef String language) {
        return updateResources(context, language);
    }

    private static boolean updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        context.createConfigurationContext(configuration);
        configuration.locale = locale;
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return true;
    }

    @Retention(RetentionPolicy.SOURCE)
    @StringDef({ENGLISH, FRENCH, SPANISH})
    public @interface LocaleDef {
        String[] SUPPORTED_LOCALES = {ENGLISH, FRENCH, SPANISH};
    }


    private static SharedPreferences getDefaultSharedPreference(Context context) {
        if (PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext()) != null)
            return PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext());
        else
            return null;
    }

    public static void setSelectedLanguageId(String id){
        final SharedPreferences prefs = getDefaultSharedPreference(Application.getInstance().getApplicationContext());
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("app_language_id", id);
        editor.apply();
    }

    public static String getSelectedLanguageId(){
        return getDefaultSharedPreference(Application.getInstance().getApplicationContext())
                .getString("app_language_id", "en");
    }
}
  

установите язык при нажатии кнопки в другом действии и перезапустите действие запуска

 public class setLaunguageActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

    }

    public void setEnglish(View view) {
        LocaleUtils.setSelectedLanguageId("en");
        Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
        startActivity(i);

    }

    public void setFrance(View view) {
        LocaleUtils.setSelectedLanguageId("fr");
        Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
        startActivity(i);

    }
}
  

Инициализируйте класс приложения в основном действии следующим образом

 public class MainActivity extends AppCompatActivity {

    TextView textInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Application.getInstance().initAppLanguage(this);
        setContentView(R.layout.activity_main);
}
  

этот код работает для меня