Changing configuration in Android during runtime

One of my Android applications need to change the locale (language) during runtime. This allows users to have language setting in application instead of requiring to change the system language.

This is what I used to do.

private void changeLocale(@NonNull final Locale locale)
{
    final Resources res = context.getResources();
    final Configuration config = res.getConfiguration();
    config.setLocale(locale);
    final Resources resources = getResources();
    resources.updateConfiguration(config, resources.getDisplayMetrics());
    // This is need for the changes to take effect
    recreate();
}

However, updateConfiguration(Configuration, DisplayMetrics) is deprecated in API level 25. It recommends using Context.createConfigurationContext(Configuration) instead.

private void changeLocale(@NonNull final Locale locale)
{
    final Resources res = context.getResources();
    final Configuration config = res.getConfiguration();
    config.setLocale(locale);
    final Context newContext = createConfigurationContext(config);
    // What should I do with the newContext???
    recreate();
}

In the documentation, it does not say anything or how to use the new Context. After some Googling, I found the way to do it.

@Override
protected void attachBaseContext(Context newBase) {
    final Resources res = context.getResources();
    final Configuration config = res.getConfiguration();
    config.setLocale(getLocale()); // getLocale() should return a Locale
    final Context newContext = createConfigurationContext(newBase);
    super.attachBaseContext(newContext);
}

Then other activity should inherit it. Then, when the Activity is created, the new Context is applied. Note that if you want current Activity to changes. You need to call recreate() to apply the effect.

I have create a ConfigurationWrapper to handle this instead of writing it directly to the Activity.

package com.joshuaavalon.android.context;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.support.annotation.NonNull;

import java.util.Locale;

/**
 * Provides static methods to create Context with other Configuration.
 */
public class ConfigurationWrapper {
    private ConfigurationWrapper() {
    }

    //Creates a Context with updated Configuration.
    public static Context wrapConfiguration(@NonNull final Context context,
                                            @NonNull final Configuration config) {
        return context.createConfigurationContext(config);
    }

    // Creates a Context with updated Locale.
    public static Context wrapLocale(@NonNull final Context context,
                                     @NonNull final Locale locale) {
        final Resources res = context.getResources();
        final Configuration config = res.getConfiguration();
        config.setLocale(locale);
        return wrapConfiguration(context, config);
    }
}

Then, you can use it like this. If you have other configuration to change, you can use wrapConfiguration instead.

@Override
protected void attachBaseContext(Context newBase) {
    // getLocale() should return a Locale. Probably read from setting.
    super.attachBaseContext(ConfigurationWrapper.wrapLocale(newContext, getLocale()));
}

ConfigurationWrapper is in my Common library for Android. Check it out if you find this solution useful.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s