Cómo actualizar la actividad después de cambiar el idioma (configuración regional) dentro de la aplicación

Los usuarios de mi aplicación pueden cambiar el idioma de la configuración de la aplicación. ¿Es posible cambiar el idioma dentro de la aplicación sin tener efecto en la configuración general del idioma? Esta pregunta sobre stackoverflow me es muy útil y la he probado. Después de cambiar el idioma, las actividades recién creadas se muestran con un nuevo idioma modificado, pero la actividad actual y las actividades creadas anteriormente que se encuentran en estado de pausa no se actualizan. ¿Cómo actualizar las actividades? También he pasado mucho tiempo tratando de hacer que el cambio de preferencia se aplique de inmediato, pero no tuvo éxito. Cuando se reinicia la aplicación, todas las actividades se crean de nuevo, por lo que ahora el idioma cambió correctamente.

android:configChanges="locale" 

también se agregó en manifiesto para todas las actividades. y también es compatible con toda la pantalla. Actualmente no he hecho nada en el método onResume () de la actividad. ¿Hay alguna forma de actualizar o actualizar la actividad (sin finalizar y comenzar de nuevo)? ¿Me estoy perdiendo algo que hacer en el método onResume ()?

Después de cambiar el idioma, las actividades recién creadas se muestran con un nuevo idioma modificado, pero la actividad actual y las actividades creadas anteriormente que se encuentran en estado de pausa no se actualizan. ¿Cómo actualizar las actividades?

Pre API 11 (Honeycomb), la forma más sencilla de mostrar las actividades existentes en un nuevo idioma es reiniciarlo. De esta forma, no se molesta en volver a cargar cada recurso usted mismo.

 private void restartActivity() { Intent intent = getIntent(); finish(); startActivity(intent); } 

Registre OnSharedPreferenceChangeListener , en su onShredPreferenceChanged() , invoque restartActivity() si se cambió la preferencia de idioma. En mi ejemplo, solo se reinicia la Actividad de preferencia, pero debería poder reiniciar otras actividades en la reanudación de actividad configurando un indicador.

Actualización (gracias @stackunderflow): a partir de la API 11 (Honeycomb) debería usar recreate() lugar de restartActivity() .

 public class PreferenceActivity extends android.preference.PreferenceActivity implements OnSharedPreferenceChangeListener { // ... @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("pref_language")) { ((Application) getApplication()).setLocale(); restartActivity(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override protected void onStop() { super.onStop(); getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); } } 

Tengo una publicación en el blog sobre este tema con más detalles, pero está en chino. El código fuente completo está en github: PreferenceActivity.java

Si imaginaba que estableces android:configChanges en manifest.xml y creas varios directorios para varios idiomas como: values-fr OR values-nl , podría sugerir este código (en la clase Activity):

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // change language by onclick a button Configuration newConfig = new Configuration(); newConfig.locale = Locale.FRENCH; onConfigurationChanged(newConfig); } }); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics()); setContentView(R.layout.main); setTitle(R.string.app_name); // Checks the active language if (newConfig.locale == Locale.ENGLISH) { Toast.makeText(this, "English", Toast.LENGTH_SHORT).show(); } else if (newConfig.locale == Locale.FRENCH){ Toast.makeText(this, "French", Toast.LENGTH_SHORT).show(); } } 

Probé este código, es correcto.

Dado que los recursos de cadena ya se habrán cargado para la configuración regional existente, las actividades ya abiertas no se mostrarán automáticamente utilizando cadenas de la nueva configuración regional. La única forma de resolver esto es volver a cargar todas las cadenas y volver a establecerlas en las vistas. Normalmente, una llamada a setContentView(...) podrá cubrir esto (dependiendo de la estructura de tu actividad), pero por supuesto tiene el efecto secundario de perder cualquier estado de vista que tengas.

 public void onResume() { super.onResume(); ... if (localeHasChanged) { setContentView(R.layout.xxx); } ... } 

Probablemente no desee volver a cargar las vistas cada vez en onResume() , sino solo cuando la configuración regional haya cambiado. Comprobar cuándo actualizar las vistas (es decir, localeHasChanged ) es una cuestión de propagar el evento de cambio de la configuración regional a las actividades anteriores. Esto podría hacerse de muchas maneras, como usar un estado estático de singleton o persistir este evento en el almacenamiento.

También podría intentar minimizar el número de Actividades que se pueden abrir cuando puede cambiar la configuración regional, por ejemplo, teniendo la selección en una de las pantallas iniciales.

Para Android 4.2 (API 17), debe usar android:configChanges="locale|layoutDirection" en su AndroidManifest.xml. Ver en Configuración cambiada no se llama sobre jellybean (4.2.1)

Puedes usar recreate(); para reiniciar su actividad cuando el cambio de idioma.

Estoy usando el siguiente código para reiniciar la actividad cuando el cambio de idioma:

 SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); Configuration config = getBaseContext().getResources().getConfiguration(); String lang = settings.getString("lang_list", ""); if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang)) { recreate(); //this is used for recreate activity Locale locale = new Locale(lang); Locale.setDefault(locale); config.locale = locale; getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); } 

Solucioné mi problema con este código

 public void setLocale(String lang) { myLocale = new Locale(lang); Resources res = getResources(); DisplayMetrics dm = res.getDisplayMetrics(); Configuration conf = res.getConfiguration(); conf.locale = myLocale; res.updateConfiguration(conf, dm); onConfigurationChanged(conf); } @Override public void onConfigurationChanged(Configuration newConfig) { iv.setImageDrawable(getResources().getDrawable(R.drawable.keyboard)); greet.setText(R.string.greet); textView1.setText(R.string.langselection); super.onConfigurationChanged(newConfig); } 

La forma en que lo hemos hecho fue usando Transmisiones:

  1. Envíe la transmisión cada vez que el usuario cambie de idioma
  2. Registre el receptor de difusión en AppActivity.onCreate() y AppActivity.onDestroy() registro en AppActivity.onDestroy()
  3. En BroadcastReceiver.onReceive() simplemente reinicie la actividad.

AppActivity es la actividad principal que todas las demás actividades subclasan.


A continuación se muestra el fragmento de mi código, no probado fuera del proyecto, pero debe darle una buena idea.

Cuando el usuario cambia el idioma

 sendBroadcast(new Intent("Language.changed")); 

Y en la actividad de los padres

 public class AppActivity extends Activity { /** * The receiver that will handle the change of the language. */ private BroadcastReceiver mLangaugeChangedReceiver; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Other code here // ... // Define receiver mLangaugeChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { startActivity(getIntent()); finish(); } }; // Register receiver registerReceiver(mLangaugeChangedReceiver, new IntentFilter("Language.changed")); } @Override protected void onDestroy() { super.onDestroy(); // ... // Other cleanup code here // ... // Unregister receiver if (mLangaugeChangedReceiver != null) { try { unregisterReceiver(mLangaugeChangedReceiver); mLangaugeChangedReceiver = null; } catch (final Exception e) {} } } } 

Esto también actualizará la actividad que cambió el idioma (si subclasifica la actividad anterior).

Esto hará que pierda datos, pero si es importante, ya debería haberse hecho cargo de esto usando Actvity.onSaveInstanceState() y Actvity.onRestoreInstanceState() (o similar).

Déjame saber tus pensamientos sobre esto.

¡Aclamaciones!

Llame a este método para cambiar la configuración regional de la aplicación:

 public void settingLocale(Context context, String language) { Locale locale; Configuration config = new Configuration(); if(language.equals(LANGUAGE_ENGLISH)) { locale = new Locale("en"); Locale.setDefault(locale); config.locale = locale; }else if(language.equals(LANGUAGE_ARABIC)){ locale = new Locale("hi"); Locale.setDefault(locale); config.locale = locale; } context.getResources().updateConfiguration(config, null); // Here again set the text on view to reflect locale change // and it will pick resource from new locale tv1.setText(R.string.one); //tv1 is textview in my activity } 

Nota: Pon tus cadenas en valor y valores- carpeta.