web-dev-qa-db-fra.com

Les ressources et la direction de la présentation sont rendues de manière incorrecte uniquement sous Android 8.0 et versions ultérieures

J'ai une application multilingue avec l'anglais comme langue principale et l'arabe comme langue secondaire.

J'appelle setLocale() dans la onCreate() de chaque Activitydans mon application:

public static void setLocale(Locale locale){
    Locale.setDefault(locale);
    Context context = MyApplication.getInstance();
    final Resources resources = context.getResources();
    final Configuration config = resources.getConfiguration();
    config.setLocale(locale);
    context.getResources().updateConfiguration(config,
            resources.getDisplayMetrics());
}

localeest l'un des éléments suivants:

![enter image description here

La méthode ci-dessus est appelée avant que super.onCreate(savedInstanceState) soit appelé.

Comme décrit dans le documentation ,

  • J'ai ajouté Android:supportsRtl="true" dans le manifeste.
  • J'ai modifié toutes les propriétés XML avec les attributs leftet righten startet endname__.
  • J'ai placé des chaînes en arabe dans le dossier res\values-ar\strings et des ressources pouvant être extraites dans le dossier res\drawable-ar (et de la même manière pour d'autres ressources).

La configuration ci-dessus fonctionne correctement. Une fois que Localea été remplacé par ar-AE, le texte et les ressources arabes sont correctement affichés dans mes activités.

Toutefois, il existe un problème de ressources et de mise en forme pour tous les appareils Android dotés de la version 8.0 et des versions supérieures.

Sur un appareil avec une version inférieure à 8.0, un écran RTL correctement ressemble à ceci:

enter image description here

Et sur tous les appareils avec 8.0+, le même écran apparaît comme suit:

enter image description here

qui est faux .

Il se trouve que la direction et les ressources s'affichent de manière incorrecte.

Il y a deux problèmes ici:

  • Le Localecorrect ne semble pas être mis à jour dans la configuration de l'application.
  • La direction du texte et des tirables est opposée à ce qu'elle devrait être.

En ce qui concerne la direction, une méthode curieuse appelée setLayoutDirection() existe que je n'avais pas remarquée auparavant.

J'aimerais savoir en quoi consiste ce problème, pourquoi cela se produit à Oreo et quelle est la solution. S'il vous plaît aider/commenter sur ce.

EDIT:

Selon le rapport Différences d'API , la méthode updateConfiguration() était en effet déconseillée dans Android 7.1 (niveau 25 de l'API).

En outre, trouvé tous les messages pertinents à ce sujet. Par ordre d'importance:

1. Android N change de langue par programmation .

2. Android context.getResources.updateConfiguration () obsolète .

3. Comment changer la langue d’application Android O/Oreo/api 26 .

4. problème d'Android RTL dans l'API 24 et les versions ultérieures lors d'un changement de paramètres régionaux

5. Changer de langue par programme (Android N 7.0 - API 24) .

6. Android N - Modifier les paramètres régionaux au moment de l'exécution .

7. bug de mise en page RTL dans Android Oreo .

12
Y.S.

La méthode updateConfiguration() était obsolète 

Maintenant nous devons utiliser createConfigurationContext()

J'ai réussi de cette façon

créer une nouvelle classe ContextWrapper

import Android.content.Context;
import Android.content.res.Configuration;
import Android.content.res.Resources;
import Android.os.Build;
import Android.os.LocaleList;

import Java.util.Locale;

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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            configuration.setLocale(newLocale);

            LocaleList localeList = new LocaleList(newLocale);
            LocaleList.setDefault(localeList);
            configuration.setLocales(localeList);

            context = context.createConfigurationContext(configuration);

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLocale(newLocale);
            context = context.createConfigurationContext(configuration);

        } else {
            configuration.locale = newLocale;
            res.updateConfiguration(configuration, res.getDisplayMetrics());
        }

        return new ContextWrapper(context);
    }}

créer une nouvelle classe de BaseActivity

import Android.content.Context;

import Android.support.v7.app.AppCompatActivity;

import Java.util.Locale;

/**
 * Created by nilesh on 20/3/18.
 */

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void attachBaseContext(Context newBase) {

        Locale newLocale;

        String lang = new PrefManager(newBase).getLanguage();

        if (lang.equals("zh_CN")) {
            newLocale = new Locale("zh");
        } else {
            newLocale = new Locale(lang);
        }


        Context context = ContextWrapper.wrap(newBase, newLocale);
        super.attachBaseContext(context);
    }
}

Créer une classe PrefManager pour stocker les paramètres régionaux

import Android.content.Context;
import Android.content.SharedPreferences;

public class PrefManager {

    private SharedPreferences.Editor editor;
    private Context mContext;
    private SharedPreferences prefs;
    private final String LANGUAGE = "language";
    private final String PREF = "user_data";

    public PrefManager(Context mContext) {
        this.mContext = mContext;
    }

    public String getLanguage() {
        this.prefs = this.mContext.getSharedPreferences(PREF, 0);
        return this.prefs.getString(LANGUAGE, "en_US");
    }

    public void setLanguage(String language) {
        this.editor = this.mContext.getSharedPreferences(PREF, 0).edit();
        this.editor.putString(LANGUAGE, language);
        this.editor.apply();
    }

}

Maintenant, vous devez étendre votre BaseActivity à toutes vos activités, comme

public class OrdersActivity extends BaseActivity

Maintenant, lorsque vous avez besoin de changer Locale, il suffit de mettre à jour la valeur dans PrefManager et de relancer votre activité. 

    PrefManager prefManager= new PrefManager(this);
    prefManager.setLanguage("zh_CN");
    //  restart your activity
4
Nilesh Rathod

La méthode Resources#updateConfiguration (Configuration config, DisplayMetrics metrics) est obsolète dans l'API de niveau 25.

La doc suggère d'utiliser Context#createConfigurationContext (Configuration overrideConfiguration)


Vous pouvez simplement créer une activité de base qui est un parent commun de toutes les activités décrites ci-dessous.

public class BaseActivity
        extends AppCompatActivity {

    private static final String LANGUAGE_CODE_ENGLISH = "en";
    private static final String LANGUAGE_CODE_ARABIC = "ar";

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(CommonUtils.getLanguageAwareContext(newBase));
    }

    private static Context getLanguageAwareContext(Context context) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(new Locale(getLanguageCode));
        return context.createConfigurationContext(configuration);
    }

    // Rewrite this method according to your needs
    private static String getLanguageCode() {
        return LANGUAGE_CODE_ARABIC;
    }
}


Remarques

  • getLanguageCode() devrait retourner le code de langue. Généralement, le code de langue ou toute autre donnée le représentant est stocké dans les préférences.
  • Pour changer de langue de manière dynamique, recréez une activité après avoir défini le code de langue approprié dans les préférences.
  • Utilisez le contexte d'activité plutôt que le contexte d'application pour accéder aux ressources spécifiques à l'environnement local. En d'autres termes, utilisez this ou ActivityName.this à partir d'activités et getActivity() à partir de fragments au lieu de getApplicationContext().
1
Anees

Resources.updateConfiguration est obsolète, utilisez plutôt ceci:

 fun setLocale(old: Context, locale: Locale): Context {
    val oldConfig = old.resources.configuration
    oldConfig.setLocale(locale)
    return old.createConfigurationContext(oldConfig)
}

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase?.let { setLocale(it, Locale("ar")) })
}

En java

private Context setLocale(Context old, Locale locale) {
    Configuration oldConfig = old.getResources().getConfiguration();
    oldConfig.setLocale(locale);
    return old.createConfigurationContext(oldConfig);
}

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(setLocale(newBase, new Locale("ar")));
}
1
svkaka

Totalement fermé l'application parce que je pense qu'il fait le cache en arrière-plan.

Utilisez le code ci-dessous et voici comment je l'ai réalisé dans mon cas. Vous pouvez également l'essayer:

 Intent mStartActivity = new Intent(ctc, SplashActivity.class);
                int mPendingIntentId = 123456;
                PendingIntent mPendingIntent = PendingIntent.getActivity(ctc, mPendingIntentId,    mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
                AlarmManager mgr = (AlarmManager)ctc.getSystemService(Context.ALARM_SERVICE);
                mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
                System.exit(0);
0
Diwakar Singh
public void setLocale(final Context ctx, final String lang) {
    AppSettings.getInstance(ctx).save(PrefKeys.language, lang);
    final Locale loc = new Locale(lang);
    Locale.setDefault(loc);
    final Configuration cfg = new Configuration();
    cfg.locale = loc;
    ctx.getResources().updateConfiguration(cfg, null);
}

Changer en anglais: setLocale(getActivity(), "en";

Changer en arabe: setLocale(getActivity(), "ar");

Après cela, vous devez redémarrer l'application pour obtenir les effets de changement de langue.

0
SHIDHIN.T.S