如何更改应用程序内部语言(Locale)后的活动
我的应用程序用户可以从应用程序的设置中更改语言。 是否可以改变应用程序内的语言,而不影响一般的语言设置? 这个问题的stackoverflow是非常有用的,我已经试过了。 更改语言新创build的活动后,更改新的语言显示,但当前的活动和以前创build的处于暂停状态的活动不更新。如何更新活动? 我也花了很多时间试图使偏好变化立即得到应用,但没有成功。 应用程序重新启动时,所有活动再次创build,所以现在语言正确更改。
android:configChanges="locale"
也join了所有活动的清单。 也支持所有屏幕。 目前我还没有在Activity的onResume()方法中做任何事情。 有没有什么办法刷新或更新活动(没有完成并重新开始)? 我在onResume()方法中错过了什么吗?
更改语言新创build的活动后,更改新的语言显示,但当前的活动和以前创build的处于暂停状态的活动不更新。如何更新活动?
Pre API 11(Honeycomb)是使现有活动以新语言显示的最简单方法,即重新启动它。 这样你就不用费心去重新加载每个资源。
private void restartActivity() { Intent intent = getIntent(); finish(); startActivity(intent); }
在onShredPreferenceChanged()
注册OnSharedPreferenceChangeListener
,如果语言首选项已更改,则调用restartActivity()
。 在我的示例中,只有PreferenceActivity重新启动,但您应该能够通过设置标志来重新开始活动恢复其他活动。
更新(谢谢@stackunderflow):从API 11(蜂窝),你应该使用recreate()
而不是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); } }
我有一个关于这个主题的博客文章 ,更详细的,但它是中文。 完整的源代码在github上: PreferenceActivity.java
如果我想象你在manifest.xml中设置android:configChanges
并为几种语言创build几个目录,例如: values-fr OR values-nl
,我可以build议这个代码(在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(); } }
我testing了这个代码,这是正确的。
由于string资源已经为现有的语言环境加载,已经打开的活动不会自动使用新语言环境中的string显示。 解决这个问题的唯一方法是重新加载所有的string,并在视图上重新设置它们。 通常情况下,调用setContentView(...)
将能够覆盖这个(取决于你的Activity结构),但是当然它有失去你所有视图状态的副作用。
public void onResume() { super.onResume(); ... if (localeHasChanged) { setContentView(R.layout.xxx); } ... }
您可能不希望在onResume()
每次都重新加载视图,但只有在语言环境已更改时才会重新加载视图。 检查何时更新视图(即localeHasChanged
)是将区域设置更改事件传播到以前的活动的问题。 这可以通过很多方式来完成,比如使用静态的单例状态或者将这个事件存储起来。
您也可以尝试最小化可以在更改区域设置时打开的“活动”数量,例如,通过将select置于其中一个初始屏幕上。
对于Android 4.2(API 17),您需要在AndroidManifest.xml中使用android:configChanges="locale|layoutDirection"
。 请参阅onConfigurationchanged不要在jellybean上调用(4.2.1)
我用这个代码解决了我的问题
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); }
调用此方法更改应用程序语言环境:
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 }
注意:把你的string的值和值 – 文件夹。
你可以使用recreate();
在语言更改时重新启动您的活动。
我正在使用以下代码在语言更改时重新启动活动:
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()); }
我们做的方式是使用广播:
- 每次用户更改语言时发送广播
- 在
AppActivity.onCreate()
注册广播接收器并在AppActivity.onCreate()
取消注册 - 在
BroadcastReceiver.onReceive()
只是重新启动活动。
AppActivity
是所有其他活动的子类的父活动。
下面是我的代码片段,没有在项目外进行testing,但应该给你一个好主意。
当用户改变语言时
sendBroadcast(new Intent("Language.changed"));
并在父母的活动
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) {} } } }
这也会刷新改变语言的活动(如果它是上面的活动的子类)。
这会让你失去任何数据,但是如果它很重要,你应该已经使用Actvity.onSaveInstanceState()
和Actvity.onRestoreInstanceState()
(或类似的)来处理这个问题。
让我知道你对此的想法。
干杯!