Android user-set Locale always get reset after onCreate?

I want to have a configurable language settings in my app.

So, in onCreate of my activity, I call Resources.updateConfiguration with the new locale.

However, after onCreate (at some time, I can't find it when), the locale is set back to the default locale.

On the code example below, the strings shown in the main layout (as inflated by setContentView) shows the "in" language version, BUT when I press the menu button, on which onCreateMenu is called, the strings is taken from the "en" (default) locale.

The log shows this:

 18337               oncreate  D  { scale=1.0 imsi=525/1 loc=intouch=3 keys=1/1/2 nav=3/1 orien=1 layout=34 uiMode=17 seq=143}
 30430        ActivityManager  I  Displayed activity yuku.coba.locale/.CobaLocaleActivity: 266 ms (total 266 ms)
 18337        KeyCharacterMap  W  No keyboard for id 65540
 18337        KeyCharacterMap  W  Using default keymap: /system/usr/keychars/qwerty.kcm.bin
 18337                 onmenu  D  { scale=1.0 imsi=525/1 loc=en_GB touch=3 keys=1/1/2 nav=3/1 orien=1 layout=34 uiMode=17 seq=143}

Between "oncreate" and "onmenu", the locale magically changes.

Please help, I have been tinkering with this with no luck.

Code snippet:

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       Configuration c = new Configuration();
       c.locale = new Locale("in");
       getResources().updateConfiguration(c, null);

       setContentView(R.layout.main);
       Log.d("oncreate", getResources().getConfiguration().toString());
   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
       Log.d("onmenu", getResources().getConfiguration().toString());
       new MenuInflater(this).inflate(R.menu.utama, menu);

       return true;
   }

Upvotes: 1

Views: 6003

Answers (4)

Lucas
Lucas

Reputation: 3591

You can use a method I wrote, to handle this situation:

/**
     * Sets app language locale also taking account system resets of the Locale; Resetting of the Locale is done right after onResume of the first Activity that is run in the application.
     * So... if the AppLanugage is set e.g. in first activitys onCreate method, this language will be reset shortly after; To counter this the method starts the Timer (if a flag is set) to
     * handle pottential Locale resets that are done by the system.
     * 
     * In case the flag alsoReloadAfterDelay is set, usually the numberOfResetsOsDoes parameter and the numberOfResetsOsDoes should be used separately from eachother; Either the timer
     * shoudl run till the numberOfResetsOsDoes is matched, or run till the timer runs out of time, irrespectively of the number of resets the os does
     * @param appContext    The application context
     * @param lang  New language to set the locale
     * @param alsoReloadAfterDelay  The flag that says whether to start a timer that will handle pottential Locale resets, that are done by Android OS;
     * @param numberOfResetsOsDoes  The number of resets the OS does after onResume method of the first activity; So far I noticed that it is happening twice (emulator 2.3.3)
     * @param resetTimerDuration    The duration of the reset timer;
     * @see <a href="https://groups.google.com/forum/?hl=en#!topic/android-developers/VEAWMCdyIWg">https://groups.google.com/forum/?hl=en#!topic/android-developers/VEAWMCdyIWg</a> 
     * @return  True if the operation succeded (if the given lang param was appliable for instance); False otherwise
     */
    public static boolean setAppLanguageLocale(final Context appContext, final String lang, boolean alsoReloadAfterDelay, final int numberOfResetsOsDoes, int resetTimerDuration)
    {       
        final String previousAppLanguage = getAppLanguage(appContext);
        final String newLang = lang.toUpperCase(Locale.US);

        if(previousAppLanguage.equals(newLang))
            return true;

        setAppLanguageLocaleP(appContext, lang);

        if(alsoReloadAfterDelay)
        {               
            new CancellableCountDownTimer(resetTimerDuration, 10)
            {
                private int aResetCounter = 0;

                @Override
                public void onTick(long millisUntilFinished)
                {
                    if(aResetCounter == numberOfResetsOsDoes)
                    {
                        this.cancel();
                        return;
                    }

                    String currentAppLanguage = getAppLanguage(appContext);

                    if(!currentAppLanguage.equals(newLang))
                    {
                        aResetCounter++;

                        setAppLanguageLocale(appContext, lang);
                    }
                }

                @Override
                public void onFinish()
                {                   
                }
            }.start();
        }

        return true;
    }

Upvotes: 0

FunkTheMonk
FunkTheMonk

Reputation: 10938

instead of getResources().updateConfiguration(c, null);

try getBaseContext().getResources().updateConfiguration(c, null);

(not getDefaultContext sorry)

Upvotes: 0

fhucho
fhucho

Reputation: 34560

Every 100ms reset the Configuration :)

Upvotes: -1

Alex Volovoy
Alex Volovoy

Reputation: 68474

I advice not force locale to something that is different from the device setting. You will run into the problems. You can move your call to onResume. It will be better, but still you're gonna fight device configuration. Again. Don't do this .

Upvotes: 0

Related Questions