Ispirato dalla calligrafia , ho finito per creare un involucro di contesto. Nel mio caso, ho bisogno di sovrascrivere la lingua del sistema per fornire agli utenti della mia app la possibilità di cambiare la lingua dell'app, ma questo può essere personalizzato con qualsiasi logica che è necessario implementare.
import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Build;
import java.util.Locale;
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
@SuppressWarnings("deprecation")
public static ContextWrapper wrap(Context context, String language) {
Configuration config = context.getResources().getConfiguration();
Locale sysLocale = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
sysLocale = getSystemLocale(config);
} else {
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.equals("") && !sysLocale.getLanguage().equals(language)) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setSystemLocale(config, locale);
} else {
setSystemLocaleLegacy(config, locale);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context = context.createConfigurationContext(config);
} else {
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
return new MyContextWrapper(context);
}
@SuppressWarnings("deprecation")
public static Locale getSystemLocaleLegacy(Configuration config){
return config.locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static Locale getSystemLocale(Configuration config){
return config.getLocales().get(0);
}
@SuppressWarnings("deprecation")
public static void setSystemLocaleLegacy(Configuration config, Locale locale){
config.locale = locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static void setSystemLocale(Configuration config, Locale locale){
config.setLocale(locale);
}
}
e per iniettare il tuo wrapper, in ogni attività aggiungi il seguente codice:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr"));
}
AGGIORNAMENTO 22/12/2020
Dopo l'implementazione della libreria di materiali Android di ContextThemeWrapper per supportare la modalità oscura, l'impostazione della lingua si interrompe e l'impostazione della lingua viene persa. Dopo mesi di grattarsi la testa, il problema è stato risolto aggiungendo il seguente codice al metodo Activity e Fragment onCreate
Context context = MyContextWrapper.wrap(this, "fr");
getResources().updateConfiguration(context.getResources().getConfiguration(), context.getResources().getDisplayMetrics());
AGGIORNAMENTO 19/10/2018
A volte dopo la modifica dell'orientamento o la pausa / ripresa dell'attività, l'oggetto Configurazione si ripristina alla configurazione di sistema predefinita e di conseguenza vedremo l'app che mostra il testo inglese "en" anche se abbiamo racchiuso il contesto con la lingua francese "fr" . Pertanto, come buona pratica, non conservare mai l'oggetto Context / Activity in una variabile globale in attività o frammenti.
inoltre, creare e utilizzare quanto segue in un MyBaseFragment o MyBaseActivity:
public Context getMyContext(){
return MyContextWrapper.wrap(getContext(),"fr");
}
Questa pratica ti fornirà una soluzione priva di bug al 100%.