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
Push Notifications in Android Platform
How to Dynamically Update a Listview on Android
What's the Best Way to Limit Text Length of Edittext in Android
Android - Cancel Asynctask Forcefully
Error Inflating Class Android.Support.Design.Widget.Navigationview
Error:Execution Failed for Task ':App:Transformclasseswithdexfordebug'
How to Get Resource Name from Resource Id
Difference Between App:Srccompat and Android:Src in Android's Layout Xml
Accessing Localhost:Port from Android Emulator
How to Make the Corners of a Button Round
How to Change the Text on the Action Bar
Noclassdeffounderror For Code in an Java Library on Android
No Resource Found That Matches the Given Name '@Style/Theme.Appcompat.Light'
How to Pass Arraylist<Customeobject> from One Activity to Another