android - synchronisierungsprobleme - google kontakte werden nicht angezeigt



Ressourcen und Layoutrichtung werden nur unter Android 8.0 und höher falsch gerendert (4)

Ich habe eine mehrsprachige App mit Primärsprache Englisch und Sekundärsprache Arabisch.

Ich rufe setLocale() im onCreate() jeder Activity in meiner App auf:

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());
}

Dabei ist das locale eines der folgenden:

Die obige Methode wird aufgerufen, bevor super.onCreate(savedInstanceState) aufgerufen wird.

Wie in der documentation ,

  • Ich habe android:supportsRtl="true" hinzugefügt android:supportsRtl="true" im Manifest.
  • Ich habe alle XML-Eigenschaften mit left und right Attributen geändert, start jeweils zu start und zu end .
  • Ich habe Zeichenfolgen in arabischer Sprache in den Ordner " res\values-ar\strings " und Zeichenressourcen in den Ordner " res\drawable-ar " gestellt (und ähnlich für andere Ressourcen).

Das obige Setup funktioniert ordnungsgemäß. Nachdem Sie das Locale in ar-AE , werden arabischer Text und Ressourcen in meinen Aktivitäten korrekt angezeigt.

Es gibt jedoch ein Problem mit den Ressourcen und der Layoutrichtung für alle Android-Geräte mit Version 8.0 und höher.

Auf einem Gerät mit einer Version unter 8.0 sieht ein RTL-Bildschirm folgendermaßen aus:

Und auf allen Geräten mit 8.0+ wird derselbe Bildschirm folgendermaßen angezeigt:

was falsch ist .

Es stellt sich heraus, dass sowohl die Richtung als auch die Ressourcen falsch angezeigt werden.

Hier gibt es zwei Probleme:

  • Das richtige Locale scheint in der gesamten App-Konfiguration nicht aktualisiert zu werden.
  • Die Richtung des Textes und der Zeichen ist entgegengesetzt zu der, die er sein sollte.

In Bezug auf die Richtung gibt es eine merkwürdige Methode namens setLayoutDirection() , die ich vorher nicht bemerkt hatte.

Ich würde gerne wissen, was dieses Problem ist, warum es in Oreo passiert und was die Lösung dafür ist. Bitte helfen / kommentieren Sie dies.

EDIT :

Laut dem API Differences-Bericht wurde die updateConfiguration() -Methode in Android 7.1 (API-Level 25) tatsächlich als veraltet eingestuft.

Finden Sie auch alle relevanten Beiträge dazu. Der Wichtigkeit nach geordnet:

1. Android N Sprache programmgesteuert ändern .

2. Android context.getResources.updateConfiguration () veraltet .

3. So ändern Sie die Sprache der Android O / Oreo / api 26-App .

4. Android RTL-Problem in API 24 und höher bei Änderung der Ländereinstellung

5. Ändern Sie die Sprache programmgesteuert (Android N 7.0 - API 24) .

6. Android N - Ändern Sie das Gebietsschema zur Laufzeit .

7. RTL-Layout-Fehler in Android Oreo .


Answer #1

Die updateConfiguration() -Methode war veraltet

Jetzt müssen wir createConfigurationContext()

Ich habe diesen Weg geschafft

Erstellen Sie eine neue Klasse 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);
    }}

Erstellen Sie eine neue Klasse von 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);
    }
}

Erstellen Sie eine PrefManager Klasse zum Speichern des Gebietsschemas

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();
    }

}

Jetzt müssen Sie Ihre BaseActivity in allen Aktivitäten wie erweitern

public class OrdersActivity extends BaseActivity

Wenn Sie nun das Locale ändern müssen, aktualisieren Sie einfach den Wert in PrefManager und starten Sie Ihre Aktivität neu

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

HINWEIS

Sie können den Quellcode von Github Repo herunterladen


Answer #2

Die Methode updateConfiguration() ist in API-Ebene 25 veraltet .

Das Dokument schlägt vor, createConfigurationContext()


Sie können einfach eine Basisaktivität erstellen, die ein gemeinsames übergeordnetes Element aller Aktivitäten ist (siehe unten).

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;
    }
}


Anmerkungen

  • getLanguageCode() sollte den Sprachcode zurückgeben. Normalerweise werden der Sprachcode oder andere Daten, die ihn darstellen, in den Einstellungen gespeichert.
  • Wenn Sie die Sprache dynamisch ändern möchten, erstellen Sie die Aktivität neu, nachdem Sie den entsprechenden Sprachcode in den Einstellungen festgelegt haben.
  • Verwenden Sie den Aktivitätskontext anstelle des Anwendungskontexts, um auf bestimmte Ressourcen für das Gebietsschema zuzugreifen. Verwenden Sie mit anderen Worten this oder ActivityName.this aus activities und getActivity() aus Fragmenten anstelle von getApplicationContext() .

Answer #3

Hat die App komplett geschlossen, weil ich denke, dass sie den Cache im Hintergrund erstellt.

Verwenden Sie den folgenden Code, wie ich ihn in meinem Fall erhalten habe. Sie können ihn auch ausprobieren:

 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);

Answer #4

Resources.updateConfiguration ist veraltet. Verwenden Sie stattdessen Folgendes:

 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")) })
}

In 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")));
}




android-8.0-oreo