Forcing a different locale works only for top acti

2019-01-27 05:33发布

I got a minor problem about app localization:

Here's the case - I have given my users an option to always use the application in Norwegian, regardless of system language.

It works just fine for the most part (I go to settings, check the box to force Norwegian, press "back" and the previous activity is displayed in Norwegian - same thing "the other way around"), however - the language change only seems to correctly update (reload resources) for the first activity in my "back stack".

To illustrate a typical scenario:

User launches the app, and is presented with the main activity (in English). From there, he selects the second activity (also in English). He then goes into settings (from the menu in the second activity) and sets the preference to force Norwegian.

When he then navigates back, the second activity is correctly updated and displayed in Norwegian (so far so good). However, when he presses "back" once more to return to the main activity, it is still displayed in English...

If he goes back out and launches the app again, the main activity is correctly displayed in Norwegian...

Are there any bright minds here with a suggestion to what I should do?

Relevant source code:

Code included in every activity to set the display language:

In onCreate: Globals.locale_default = Locale.getDefault().getDisplayLanguage();

public void onStart() {
    super.onStart();
    forceNorwegian = settings.getBoolean(getString(R.string.pref_key_forceNorwegian).toString(), false);
       if (forceNorwegian) {
           languageCheck("no");
       } else {
            Globals.locale = null;
            languageCheck(Globals.locale_default);
       }
}

public void languageCheck(String lang) {
    Globals.locale = new Locale( lang );
    // Check the current system locale and change it to Norwegian if it's not already the default
    Globals.checkLocale( this );
    if (Globals.language_changed) {
        // Restart activity
        Intent restart = getIntent();
        finish();
        Globals.language_changed = false;
        startActivity(restart);
    }
}

Globals.java:

public class Globals {

public static Locale locale = null;
    public static String locale_default = null;
    public static boolean language_changed = false;

    public static void checkLocale( Activity a ) {
        if( locale == null )
            return;

        Configuration config = a.getBaseContext().getResources().getConfiguration();
        if( !config.locale.equals( locale ) )
        {  // Change to the new locale.  Everything will need to be closed or reloaded.
            config.locale = locale;
            a.getBaseContext().getResources().updateConfiguration( config, null );
            language_changed = true;
        }
    }
}

2条回答
该账号已被封号
2楼-- · 2019-01-27 06:16

I think its the line

  Configuration config = a.getBaseContext().getResources().getConfiguration();

getBaseContext() will only get you the reference to the Activity from inside another Acitivty. Hence, that's why it reflects the changes when you return back to the previous Activity but not the main application

Use getApplicationConext() instead that reflects changes throughout the application. This will tie the changes to the entire lifecycle of your application, thus every Activity in your app

查看更多
冷血范
3楼-- · 2019-01-27 06:18

The problem may be coming from the fact that the boolean Globals.language_changed is static, and therefore when languageCheck is called from the top activity, this boolean becomes false before languageCheck is called from the back activity. You might put in some checks to see if Activit(ies) earlier in the hierarchy are open, and if so keep the boolean set as true in case the user presses the Back button. Another option would be some logic that reloads all open Activities at once when the new locale is selected.

-- EDIT -- On further examination, I don't think this is quite your problem, since you are also updating the boolean in onStart for each activity (I missed this part when I read it the first time). Perhaps the locale changed when one of the Activities higher in the stack changed it, but the Activities lower in the stack just need to refresh. Does an orientation change on one of the lower Activities change it from English to Norwegian?

-- EDIT 2 -- The easiest way to check if that is the problem, would be to add some logging into Globals.checkLocale to see whether or not this conditional statement is true:

if( !config.locale.equals( locale ) )

If that turns out to be the problem, then one possible solution would be to save a local Locale instance in each Activity rather than a global one, and compare to that one. For example, you could grab a Locale instance in each Activity's onCreate method:

myLocale = getBaseContext().getResources().getConfiguration().locale;

Then, instead of calling Globals.checkLocal, just do the following conditional statement (in each Activity's languageCheck method):

if( Globals.locale != null && !Globals.locale.equals( myLocale ) )
{
    Configuration config = getBaseContext().getResources().getConfiguration();
    config.locale = Globals.locale;
    getBaseContext().getResources().updateConfiguration( config, null );
    Intent restart = getIntent();
    finish();
    startActivity( restart );
}

Upon restarting, the Activity's onCreate method would get called again, which would update myLocale to the correct value. This is just a quick solution, not necessarily the best one.. you could expand on this to move some of that code into a method in Globals if you wanted for example, or use a different location than onCreate to get the local Locale instance for each Activity.

查看更多
登录 后发表回答