Как обновить активность после изменения языка (локали) внутри приложения


пользователи моего приложения могут изменить язык из настроек приложения. Можно ли изменить язык внутри приложения, не влияя на общие языковые настройки ? Этот вопрос stackoverflow очень полезен для меня, и я попробовал его. После изменения языка вновь созданные действия отображаются с измененным новым языком, но текущая деятельность и ранее созданные действия, которые находятся в состоянии паузы, не обновляются.Как обновить деятельность ? Я также провел много времени, пытаясь сделать изменение предпочтений, которые будут применены немедленно, но не удалось. При перезапуске приложения все действия создаются заново, поэтому теперь язык изменен правильно.

android:configChanges="locale" 

также добавил в манифест для всех видов деятельности. а также поддерживает весь экран. В настоящее время я ничего не сделал в методе onResume() activity. Есть ли способ обновить или обновить активность (без завершения и повторного запуска) ? Я что-то пропустил в методе onResume ()?

8 52

8 ответов:

после изменения языка вновь созданные действия отображаются с измененным новым языком, но текущая деятельность и ранее созданные действия, которые находятся в состоянии паузы, не обновляются.Как обновить деятельность ?

Pre API 11 (Honeycomb), самый простой способ сделать существующие действия, которые будут отображаться на новом языке, чтобы перезапустить его. Таким образом, вы не потрудитесь перезагрузить каждый ресурс самостоятельно.

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

зарегистрировать OnSharedPreferenceChangeListener, in его 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

если бы я представлял себе, что вы установите android:configChanges in манифест.xml и создать несколько каталогов для нескольких языков, таких как:values-fr OR values-nl, я мог бы предложить этот код(в классе активности):

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

Я проверил этот код, это правильно.

поскольку строковые ресурсы уже будут загружены для существующей локали, уже открытые действия не будут автоматически отображаться с использованием строк из новой локали. Единственный способ решить эту проблему-перезагрузить все строки и снова установить их в представлениях. Как правило, вызов setContentView(...) сможет покрыть это (в зависимости от вашей структуры активности), но, конечно, это имеет побочный эффект потери любого состояния просмотра, которое у вас было.

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

вы, вероятно, не хотите, чтобы перезагрузить представления каждый раз в onResume(), но только если локаль изменилась. Проверка времени обновления представлений (т. е. localeHasChanged) - это вопрос распространения события изменения локали на предыдущие действия. Это может быть сделано многими способами, такими как использование статического состояния синглтона или сохранение этого события в хранилище.

вы также можете попытаться минимизировать количество действий, которые могут быть открыты, когда вы можете изменить локаль, например, выбрав один из начальных экранов.

для Android 4.2 (API 17), Вам нужно использовать android:configChanges="locale|layoutDirection" в вашем AndroidManifest.XML. Смотрите onConfigurationchanged не вызывается через jellybean (4.2.1)

можно использовать 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());
}

Я решил свою проблему с этим кодом

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

    }

то, как мы это сделали, было использование трансляций:

  1. отправить трансляцию каждый раз, когда пользователь меняет язык
  2. зарегистрировать широковещательный приемник в AppActivity.onCreate() и регистрацию в AppActivity.onDestroy()
  3. на BroadcastReceiver.onReceive() просто перезапустите деятельность.

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() (или похожие).

позвольте мне знать ваши мысли о этот.

Ура!

вызовите этот метод, чтобы изменить приложение язык:

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-folder.