Android Context.Getresources.Updateconfiguration() Deprecated

Android context.getResources.updateConfiguration() deprecated

Inspired by Calligraphy, I ended up creating a context wrapper.
In my case, I need to overwrite system language to provide my app users with the option of changing app language but this can be customized with any logic that you need to implement.

    import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Build;

import java.util.Locale;

public class MyContextWrapper extends ContextWrapper {

public MyContextWrapper(Context base) {
super(base);
}

@SuppressWarnings("deprecation")
public static ContextWrapper wrap(Context context, String language) {
Configuration config = context.getResources().getConfiguration();
Locale sysLocale = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
sysLocale = getSystemLocale(config);
} else {
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.equals("") && !sysLocale.getLanguage().equals(language)) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setSystemLocale(config, locale);
} else {
setSystemLocaleLegacy(config, locale);
}

}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context = context.createConfigurationContext(config);
} else {
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
return new MyContextWrapper(context);
}

@SuppressWarnings("deprecation")
public static Locale getSystemLocaleLegacy(Configuration config){
return config.locale;
}

@TargetApi(Build.VERSION_CODES.N)
public static Locale getSystemLocale(Configuration config){
return config.getLocales().get(0);
}

@SuppressWarnings("deprecation")
public static void setSystemLocaleLegacy(Configuration config, Locale locale){
config.locale = locale;
}

@TargetApi(Build.VERSION_CODES.N)
public static void setSystemLocale(Configuration config, Locale locale){
config.setLocale(locale);
}
}

and to inject your wrapper, in every activity add the following code:

@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr"));
}

UPDATE 22/12/2020
After android Material library implementation of ContextThemeWrapper to support dark mode, the language setting would break and language setting is lost. After months of head scratching, problem was resolved by adding the following code to Activity and Fragment onCreate method

Context context = MyContextWrapper.wrap(this/*in fragment use getContext() instead of this*/, "fr");
getResources().updateConfiguration(context.getResources().getConfiguration(), context.getResources().getDisplayMetrics());

UPDATE 10/19/2018
Sometimes after orientation change, or activity pause/resume the Configuration object resets to default system Configuration and in result we will see the app displaying English "en" text even though we wrapped the context with French "fr" locale. Therefore and as a good practice, never retain the Context/Activity object in a global variable in activities or fragments.

furthermore, create and use the following in a MyBaseFragment or MyBaseActivity:

public Context getMyContext(){
return MyContextWrapper.wrap(getContext(),"fr");
}

This practice will provide you with 100% bug free solution.

Resources.UpdateConfiguration is obsolete

context.getResources().updateConfiguration() has been deprecated in Android API 25 and it is advised to use context.createConfigurationContext() instead.

public override Resources Resources
{
get
{
Configuration config = new Configuration();
config.SetToDefaults();

Context context = CreateConfigurationContext(config);
Resources resources = context.Resources;

return resources;
}
}

Check Android context.getResources.updateConfiguration() deprecated

Update

If you want to change the font size, you should override the method AttachBaseContext.

Java

protected override void AttachBaseContext(Context @base)
{
// base.AttachBaseContext(@base);
Configuration config = new Configuration();
config.SetToDefaults();
config.FontScale = 1.0f;
Context context = @base.CreateConfigurationContext(config);
base.AttachBaseContext(context);
}

Kotlin

override fun attachBaseContext(newBase: Context) {

val config = Configuration();
config.setToDefaults();
config.setLocale(Locale("mr"))

super.attachBaseContext(newBase.createConfigurationContext(config));
}

Deprecated updateConfiguration() - Android

Resolved my problem. I use from this LINK then in my activity use from bellow code :

Context context = MyContextWrapper.wrap(this, "en");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(context.getResources().getLayout(R.layout.activity_main), null);
this.setContentView(view);

Android Resources.UpdateConfiguration(Configuration, DisplayMetrics) deprecated

Not sure if it's your need,you could change the attachBaseContext method like this,it could work:

protected override void AttachBaseContext(Context @base)
{
Configuration overrideConfiguration = new Configuration();
overrideConfiguration = @base.Resources.Configuration;
overrideConfiguration.SetToDefaults();
Context context = @base.CreateConfigurationContext(overrideConfiguration);
base.AttachBaseContext(context);
}

Android set app language according the device language

Ok, so I solved it this way:

created a ContextWrapper in separate java file:

public class ContextWrapper extends android.content.ContextWrapper {

public ContextWrapper(Context base) {
super(base);
}

public static ContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(newLocale);

LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);

context = context.createConfigurationContext(configuration);

} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}

return new ContextWrapper(context);
}

}

and then in my MainActivity I used it like this:

     @Override
protected void attachBaseContext(Context newBase) {

String languageToLoad;
String lng;
Locale locale;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
languageToLoad = Resources.getSystem().getConfiguration().getLocales().get(0).getLanguage();
}
else { languageToLoad = Resources.getSystem().getConfiguration().locale.getLanguage();
}

lng = "sk".equals(languageToLoad) ? "en" : "sk";
locale = new Locale(lng);Locale.setDefault(locale);

Context context = ContextWrapper.wrap(newBase, locale);
super.attachBaseContext(context);
}

Seems working fine now

android locale and updateConfiguration are deprecated

ok i solved it by using this answer of @Bassel Mourjan

i have one base activity and remaining are fragments, below is my code
(i tested this code in android 7.1.1 (genymotion emu) and it works)

see (use) MyContextWrapper class from above link.

in my MainActivity on button click i am opening activity for result from that activity i am getting language selected by user e.g : english,hindi,marathi

MainActivity :

     // i use shared preference to save my language so that when user close 
//app and open it, then his previous language will be set
@Override
public void attachBaseContext(Context newBase)
{
SharedPreferences preferences1 = newBase.getSharedPreferences("global",newBase.MODE_PRIVATE);
String lang=preferences1.getString("set_language","en"); // at start no language selected so default is english
super.attachBaseContext(MyContextWrapper.wrap(newBase,lang));
}



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

navigation_header_language.setOnClickListener(this);//Language button
}

@Override
public void onClick(View v)
{

switch (v.getId())
{
case R.id.navigation_header_language:

Intent i = new Intent(this, LanguageActivity.class);
startActivityForResult(i, 101);

break;
}
}

// when user selects language i store it in shared preference and set result
// as RESULT_OK and here in onActivityResult's result_ok i simply recreate activity
//so that attachBaseContext called again and language set as we want
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 101) {
if(resultCode == Activity.RESULT_OK)
{
this.recreate();
}

if (resultCode == Activity.RESULT_CANCELED) {
//Write your code if there's no result
}
}
}

Here is LanguageActivity which is i am calling from Main activity for result

      public class LanguageActivity extends AppCompatActivity
{
private CardView english_language,hindi_language,marathi_language;
private SharedPreferences preferences;
private SharedPreferences.Editor editor;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_language);

english_language=(CardView)findViewById(R.id.english_language);
hindi_language=(CardView)findViewById(R.id.hindi_language);
marathi_language=(CardView)findViewById(R.id.marathi_language);

preferences =getSharedPreferences("global",MODE_PRIVATE);

english_language.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
editor = preferences.edit();
editor.putString("set_language","en");
editor.commit();
setResultCode();
}
});

hindi_language.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
editor = preferences.edit();
editor.putString("set_language","hi");
editor.commit();
setResultCode();
}
});

marathi_language.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
editor = preferences.edit();
editor.putString("set_language","mr");
editor.commit();
setResultCode();
}
});
}

private void setResultCode()
{
Intent returnIntent = new Intent();
setResult(Activity.RESULT_OK,returnIntent);
finish();
// when this activity close, onActivityResult method call from Mainactivity
//and there i used this.recreate() which will recreate mMainactivity an
//attachBaseContext will be called once again
}
}


Related Topics



Leave a reply



Submit