Language not changing in all activities

I'm developing and application with multiple activities. One of them is the "Settings" activity, which have an option to change the app language.

Here is how I handle the change language in the Settings activity:

final ListPreference language = (ListPreference) findPreference("language");
    language.setSummary(Utils.getStringPreferences(context, "not-found", "language", Utils.USER_PREFS));
    language.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (newValue.toString().equals("English"))
                Utils.setStringPreferences(context, "English", "language", Utils.USER_PREFS);
            else if (newValue.toString().equals("Español"))
                Utils.setStringPreferences(context, "Español", "language", Utils.USER_PREFS);
            analysis_performance.setSummary(newValue.toString());
            restartActivity();
            return false;
        }
    });

This is the function that I'm using to change the language, invoked in all activities before "setContentView(R.layout.layout);" method:

public static void updateLanguage(Context context) {
    String language = getStringPreferences(context, "not-found", "language", USER_PREFS);
    String country = null;
    if (!"not-found".equals(language)) {
        if ("English".equals(language)) {
            language = "en";
            country = "US";
        } else if ("Español".equals(language)) {
            language = "es";
            country = "ES";
        }
        Locale locale = new Locale(language, country);
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.locale = locale;
        context.getResources().updateConfiguration(config, null);
    }
}

Apparently it works, but only for some activities. If I want to make all the activities have the same language I have to restart the app after I've used the above function.

This is the navigation between activities:

- MainActivity
    - Settings
        - Activity_1
    - Activity_2

Activities correctly changed the language: Activity_1 and Activity_2

Activities not changed the language: MainActivity and Settings

The SettingsActivity:

Context context;

private AppCompatDelegate mDelegate;

List<String> allLaunchers;
List<String> allLaunchersPackages;
BrowserSpinnerAdapter adapter;

private final String TAG = Settings.class.getSimpleName();

Resources res;

@Override
protected void onCreate(Bundle savedInstanceState) {
    getDelegate().installViewFactory();
    getDelegate().onCreate(savedInstanceState);
    super.onCreate(savedInstanceState);
    Utils.updateLanguage(this);
    setContentView(R.layout.activity_settings);
    setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

    addPreferencesFromResource(R.xml.settings);

    context = this;
    res = getResources();

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // Display navigation button
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    final ListPreference browser_selection = (ListPreference) findPreference("browser_analysis");
    fillBrowserSelection();
    browser_selection.setSummary(allLaunchers.get(allLaunchersPackages.indexOf(Utils.getStringPreferences(context, "not-found", "browser", Utils.USER_PREFS))));
    browser_selection.setEntries(allLaunchers.toArray(new CharSequence[allLaunchers.size()]));
    browser_selection.setEntryValues(allLaunchersPackages.toArray(new CharSequence[allLaunchersPackages.size()]));
    browser_selection.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Utils.setStringPreferences(context, newValue.toString(), "browser", Utils.USER_PREFS);
            browser_selection.setSummary(allLaunchers.get(allLaunchersPackages.indexOf(newValue.toString())));
            return false;
        }
    });

    final ListPreference security_level = (ListPreference) findPreference("security_level");
    security_level.setSummary(Utils.getIntPreferences(context, -1, "security_level", Utils.USER_PREFS)+"");
    security_level.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Utils.setIntPreferences(context, Integer.parseInt(newValue.toString()), "security_level", Utils.USER_PREFS);
            security_level.setSummary(newValue.toString());
            return false;
        }
    });

    final ListPreference analysis_performance = (ListPreference) findPreference("performance");
    analysis_performance.setSummary(Utils.getStringPreferences(context, "not-found", "performance", Utils.USER_PREFS));
    analysis_performance.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Utils.setStringPreferences(context, newValue.toString(), "performance", Utils.USER_PREFS);
            analysis_performance.setSummary(newValue.toString());
            return false;
        }
    });

    final ListPreference language = (ListPreference) findPreference("language");
    language.setSummary(Utils.getStringPreferences(context, "not-found", "language", Utils.USER_PREFS));
    language.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (newValue.toString().equals("English"))
                Utils.setStringPreferences(context, "English", "language", Utils.USER_PREFS);
            else if (newValue.toString().equals("Español"))
                Utils.setStringPreferences(context, "Español", "language", Utils.USER_PREFS);
            language.setSummary(newValue.toString());
            Utils.updateLanguage(Settings.this);

            recreate();
            return false;
        }
    });
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.i(TAG, "onConfigurationChanged");

    getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
    setContentView(R.layout.activity_settings);
    setTitle(R.string.title_activity_settings);

    // Checks the active language
    if (newConfig.locale == Locale.ENGLISH) {
        Toast.makeText(this, "English", Toast.LENGTH_SHORT).show();
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

public ActionBar getSupportActionBar() {
    return getDelegate().getSupportActionBar();
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    getDelegate().onPostCreate(savedInstanceState);
}

@Override
public void setContentView(@LayoutRes int layoutResID) {
    getDelegate().setContentView(layoutResID);
}

@Override
protected void onPostResume() {
    super.onPostResume();
    getDelegate().onPostResume();
}

@Override
protected void onStop() {
    super.onStop();
    getDelegate().onStop();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    getDelegate().onDestroy();
}

private void setSupportActionBar(@Nullable Toolbar toolbar) {
    getDelegate().setSupportActionBar(toolbar);
}

private AppCompatDelegate getDelegate() {
    if (mDelegate == null) {
        mDelegate = AppCompatDelegate.create(this, null);
    }
    return mDelegate;
}

SOLUTION !!!

After being in a chat with Rasi we finally solve this by creating this method to fill the layout components, as he recommended in option 1 (option 2 was also a way to solve this but I prefer this way so the user don't have to navigate in the app):

private void fillSettings() {

    setContentView(R.layout.activity_settings);
    setTitle(R.string.title_activity_settings);

    setPreferenceScreen(null);
    addPreferencesFromResource(R.xml.settings);

    context = this;
    res = getResources();

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // Display navigation button
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    final ListPreference browser_selection = (ListPreference) findPreference("browser_analysis");
    fillBrowserSelection();
    browser_selection.setSummary(allLaunchers.get(allLaunchersPackages.indexOf(Utils.getStringPreferences(context, "not-found", "browser", Utils.USER_PREFS))));
    browser_selection.setEntries(allLaunchers.toArray(new CharSequence[allLaunchers.size()]));
    browser_selection.setEntryValues(allLaunchersPackages.toArray(new CharSequence[allLaunchersPackages.size()]));
    browser_selection.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Utils.setStringPreferences(context, newValue.toString(), "browser", Utils.USER_PREFS);
            browser_selection.setSummary(allLaunchers.get(allLaunchersPackages.indexOf(newValue.toString())));
            return false;
        }
    });

    final ListPreference security_level = (ListPreference) findPreference("security_level");
    security_level.setSummary(Utils.getIntPreferences(context, -1, "security_level", Utils.USER_PREFS)+"");
    security_level.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Utils.setIntPreferences(context, Integer.parseInt(newValue.toString()), "security_level", Utils.USER_PREFS);
            security_level.setSummary(newValue.toString());
            return false;
        }
    });

    final ListPreference analysis_performance = (ListPreference) findPreference("performance");
    performance = Utils.getStringPreferences(context, "not-found", "performance", Utils.USER_PREFS);
    if (performance.equals(Utils.FOREGROUND)) analysis_performance.setSummary(res.getString(R.string.text_foreground));
    else if (performance.equals(Utils.BACKGROUND)) analysis_performance.setSummary(res.getString(R.string.text_background));
    analysis_performance.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (newValue.equals(res.getString(R.string.text_foreground))) performance = Utils.FOREGROUND;
            else if (newValue.equals(res.getString(R.string.text_background))) performance = Utils.BACKGROUND;
            Utils.setStringPreferences(context, performance, "performance", Utils.USER_PREFS);
            Log.i(TAG, performance);
            analysis_performance.setSummary(newValue.toString());
            return false;
        }
    });

    final ListPreference language = (ListPreference) findPreference("language");
    language.setSummary(Utils.getStringPreferences(context, "not-found", "language", Utils.USER_PREFS));
    language.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (newValue.toString().equals("English"))
                Utils.setStringPreferences(context, "English", "language", Utils.USER_PREFS);
            else if (newValue.toString().equals("Español"))
                Utils.setStringPreferences(context, "Español", "language", Utils.USER_PREFS);
            language.setSummary(newValue.toString());
            updateLanguage(Settings.this);
            fillSettings();
            return false;
        }
    });


}

And use it in the "onCreate" like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    getDelegate().installViewFactory();
    getDelegate().onCreate(savedInstanceState);
    super.onCreate(savedInstanceState);
    fillSettings();
}

Upvotes: 2

Views: 2075

Answers (1)

Rahul
Rahul

Reputation: 10625

You have write code to change language in a onCreate() method. So If you come back to your MainActivity and SettingsActivity after changing language it won't reflect because onCreate() will never call for the activities which are coming from stack. Either you have to take advantage of onResume() method of Activity.

But still you won't able to see the changed values on UI because View is already drawn on screen. Now you have to two options according to me -

  1. Check Locale changed in onResume() and redraw view or initialise string resources again. Make sure to call a method directly from an Activity which is changing Locale because onResume() will not call of that Activity.
  2. Move user to the splash screen and launch your App with a new locale. In this case onCreate() will work.
  3. You can override onConfigurationChanged() and check there locale is changed or not. If locale changed then reload new strings.

Upvotes: 2

Related Questions