如何在应用程序内部更改语言(Locale)后刷新活动

时间:2011-11-08 10:47:54

标签: android

我的应用程序用户可以从应用程序的设置更改语言。是否可以更改应用程序内的语言而不影响一般语言设置? This question of stackoverflow对我非常有用,我尝试过。更改语言后,新创建的活动将显示更改的新语言,但当前活动和以前创建的处于暂停状态的活动不会更新。如何更新活动? 我也花了很多时间试图让偏好改变立即应用但没有成功。重新启动应用程序时,会再次创建所有活动,因此现在语言已正确更改。

android:configChanges="locale" 

还在清单中添加了所有活动。并且还支持所有屏幕。 目前我还没有在activity的onResume()方法中做过任何事情。 有没有办法刷新或更新活动(没有完成并重新开始)?我在onResume()方法中遗漏了一些事情吗?

9 个答案:

答案 0 :(得分:65)

  

更改语言后,新创建的活动会显示更改的新语言,但当前活动和之前创建的处于暂停状态的活动不会更新。如何更新活动?

Pre API 11(Honeycomb),使现有活动以新语言显示的最简单方法是重新启动它。通过这种方式,您可以自己重新加载每个资源。

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

如果语言偏好设置已更改,请在OnSharedPreferenceChangeListener注册onShredPreferenceChanged(),调用restartActivity()。在我的示例中,仅重新启动了PreferenceActivity,但您应该能够通过设置标志来重新启动活动恢复中的其他活动。

更新(感谢@stackunderflow):从API 11(Honeycomb)开始,您应该使用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);
    }
}

我在这个主题上有一个博客post,有更多细节,但它是中文的。完整的源代码在github上:PreferenceActivity.java

答案 1 :(得分:23)

如果我想象你在 manifest.xml 中设置android:configChanges并为多种语言创建了几个目录,例如: values-fr OR values-nl ,我可以建议这段代码(在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();
    }
}

我测试了这段代码,这是正确的。

答案 2 :(得分:10)

由于已经为现有语言环境加载了字符串资源,因此使用新语言环境中的字符串不会自动显示已打开的活动。解决此问题的唯一方法是重新加载所有字符串并在视图上再次设置它们。通常情况下,对setContentView(...)的调用将能够涵盖这一点(取决于您的活动结构),但当然它会有失去任何视图状态的副作用。

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

您可能不希望在onResume()中每次都重新加载视图,但仅限于语言环境已更改时。检查何时更新视图(即localeHasChanged)是将区域设置更改事件传播到先前的活动。这可以通过多种方式完成,例如使用静态单例状态或将此事件持久存储。

您还可以尝试最小化可以更改区域设置时可以打开的活动数量,例如选择是在初始屏幕之一。

答案 3 :(得分:8)

对于Android 4.2(API 17),您需要在AndroidManifest.xml中使用android:configChanges="locale|layoutDirection"。见onConfigurationchanged is not called over jellybean(4.2.1)

答案 4 :(得分:5)

当语言发生变化时,您可以使用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());
}

答案 5 :(得分:4)

我用这段代码解决了我的问题

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

    }

答案 6 :(得分:4)

我们这样做的方式是使用广播:

  1. 每次用户更改语言时发送广播
  2. AppActivity.onCreate()中注册广播接收器,并在AppActivity.onDestroy()
  3. 中取消注册
  4. BroadcastReceiver.onReceive()中重启活动。
  5. AppActivity是所有其他活动子类的父活动。


    以下是我的代码中的代码段,未在项目外测试,但应该给你一个好主意。

    当用户更改语言

    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()(或类似)来处理此问题。

    让我知道你对此的看法。

    干杯!

答案 7 :(得分:3)

此方法将在所有API级别的设备上使用。

  1. 对BaseBaseContext使用Base Activity来设置语言环境语言并将该活动扩展到所有活动

    open class  BaseAppCompactActivity() : AppCompatActivity() {
    
        override fun attachBaseContext(newBase: Context) {
            super.attachBaseContext(LocaleHelper.onAttach(newBase))    
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)           
        }
    }
    
  2. 使用应用程序attachBaseContext和onConfigurationChanged设置区域设置语言

    public class MyApplication extends Application {
        private static MyApplication application;
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        public static MyApplication getApplication() {
            return application;
        }
    
        /**
         * overide to change local sothat language can be chnaged from android device  nogaut and above
         */
        @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(LocaleHelper.INSTANCE.onAttach(base));
        }
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            setLanguageFromNewConfig(newConfig);
            super.onConfigurationChanged(newConfig);
        }
    
        /*** also handle chnage  language if  device language chnaged **/
        private void setLanguageFromNewConfig(Configuration newConfig){
            Prefs.putSaveLocaleLanguage(this,  selectedLocaleLanguage );
            LocaleHelper.INSTANCE.onAttach(this);
        }
    
  3. 使用语言环境帮助程序来处理语言更改,这种方法适用于所有设备

    object LocaleHelper {
        private var defaultLanguage  :String = KycUtility.KYC_LANGUAGE.ENGLISH.languageCode
    
        fun onAttach(context: Context, defaultLanguage: String): Context {
            return setLocale(context, defaultLanguage)
        }
    
    
    
        fun setLocale(context: Context, language: String): Context {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                updateResources(context, language)
            } else updateResourcesLegacy(context, language)
    
        }
    
    
        @TargetApi(Build.VERSION_CODES.N)
        private fun updateResources(context: Context, language: String): Context {
            val locale = Locale(language)
            Locale.setDefault(locale)
    
            val configuration = context.getResources().getConfiguration()
            configuration.setLocale(locale)
            configuration.setLayoutDirection(locale)
    
            return context.createConfigurationContext(configuration)
        }
    
        private fun updateResourcesLegacy(context: Context, language: String): Context {
            val locale = Locale(language)
            Locale.setDefault(locale)
    
            val resources = context.getResources()
    
            val configuration = resources.getConfiguration()
            configuration.locale = locale
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                configuration.setLayoutDirection(locale)
            }
            resources.updateConfiguration(configuration, resources.getDisplayMetrics())
            return context
        }
    }
    

答案 8 :(得分:2)

调用此方法更改应用区域设置:

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

}

注意:将字符串放在value和values-文件夹中。