SharedPrefs is resetting after Setting Locale of the Android Application - android

I've create an activity to change the locale of the application to load resources of the selected language and I restart the application,moreover I'm keeping an integer value as the app state using sharedpreferences,after setting the locale via the following code,the next time that I open the application the mentioned state does not have the correct value!!!!But,when I remove the language setting there isn't any problem with the state of the application!
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
/*
* Intent refresh = new Intent(this, AndroidLocalizeActivity.class);
* startActivity(refresh); finish();
*/
PrefManager _p = new PrefManager(getApplicationContext(), PrefConfigNames.LANGUAGE_APP_CONFIG);
_p.setStringValue(GeneralPrefKeyNames.LANGUAGE, lang);
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
setResult(RESULT_OK, null);
finish();
I cannot get what happens to sharedpreferences(I've used open source securepreferences (CodeProject article)in this app)
here!!!
Thanks in advance
Edit#1
PrefManager.java
public class PrefManager {
private SecurePreferences _securePreferences = null;
public PrefManager(Context context, String PrefName)
{
_securePreferences = new SecurePreferences(context, PrefName);
}
public void setStringValue(String key, String value)
{
_securePreferences.edit().putString(key, value).commit();
}
}
Edit#2
Something which is so weird is that the state of the application stored in the sharedprefs has the correct value when I debug or run the application from eclipse (debug or run as an android application)!!!but when I rerun it on the phone it has the default value!!!Please help me solve this issue!
Edit#3
I found out that there was a problem with relaunching the application using the following lines,is there another way to relaunch the app without any problem???Or even a better way (to update the language without relaunching the app)?
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
I've tried the following link to achieve the second mentioned approach
Changing locale: Force activity to reload resources?
,but it is not being raised after the following line
res.updateConfiguration(conf, dm);
Thanks in advance

I finally got the solution,in the onPause method I save the currently saved language in the sharedprefs and after changing the locale in the setting activity and returning to the previous activity in the onResume method I compare the newly saved lang with the value kept in the onPause,and if these two are not equal I call recreate method.
#Override
protected void onResume()
{
super.onResume();
SharedPreferences _sPreferences = getSharedPreferences(PrefConfigNames.LANGUAGE_APP_CONFIG,
Context.MODE_PRIVATE);
String resumeLang = _sPreferences.getString(GeneralPrefKeyNames.LANGUAGE, "En");
if (!currentLang.equals(resumeLang))
recreate();
};
#Override
protected void onPause()
{
SharedPreferences _sPreferences = getSharedPreferences(PrefConfigNames.LANGUAGE_APP_CONFIG,
Context.MODE_PRIVATE);
currentLang = _sPreferences.getString(GeneralPrefKeyNames.LANGUAGE, "En");
super.onPause();
};

You should commit() the values

Related

Change Language of the application programmatically without refreshing the whole app

I'm trying to change the language of the application according to the user's input. I tried using this code to change the language of the application and it's working pretty fine.
public void setLocale(String lang) {
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
Intent refresh = new Intent(MainActivity.this, MainActivity.class);
startActivity(refresh);
}
But the problem is that app has to restart/refresh in order to reload the resources.
Is this the correct approach to set the language of the app programmatically?
Is there any other way to change the language without refreshing the app?
Try with recreate() on your activity. This approach was successful in my case. If you are on Fragment, then use getActivity().recreate();
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.APP_STATE.SAVED_LOCALE, localeString);
editor.apply();
getActivity().recreate();
Override following method of your activity:
#Override
protected void attachBaseContext(Context newBase) {
SharedPreferences prefs = newBase.getSharedPreferences(Constants.APP_STATE.STATE_SHARED_PREFERENCES, MODE_PRIVATE);
String localeString = prefs.getString(Constants.APP_STATE.SAVED_LOCALE, Constants.DEFAULTS.DEFAULT_LOCALE);
Locale myLocale = new Locale(localeString);
Locale.setDefault(myLocale);
Configuration config = newBase.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocale(myLocale);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N){
Context newContext = newBase.createConfigurationContext(config);
super.attachBaseContext(newContext);
return;
}
} else {
config.locale = myLocale;
}
super.attachBaseContext(newBase);
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
When user set wanted locale, what you want to do is to save it into some string in SharedPreferences and call recreate() of activity. This will then call attachBaseContext(Context context) and in this method proper locale will be set to configuration, then new context will be created with this configuration. After that, new context will be sent to super class which will update application context and proper locale will be shown.
It is also good because locale is automatically set when starting app next time.
Change locale is a Configuration which leads your acitivity restart. There are many other things have the same effect like orientation , keyboardHidden. Take care of your activity's states.
If restarting your activity requires that you recover large sets of
data, re-establish a network connection, or perform other intensive
operations, then a full restart due to a configuration change might be
a slow user experience. Also, it might not be possible for you to
completely restore your activity state with the Bundle that the system
saves for you with the onSaveInstanceState() callback—it is not
designed to carry large objects (such as bitmaps) and the data within
it must be serialized then deserialized, which can consume a lot of
memory and make the configuration change slow. In such a situation,
you can alleviate the burden of reinitializing part of your activity
by retaining a Fragment when your activity is restarted due to a
configuration change. This fragment can contain references to stateful
objects that you want to retain.
Not the best-practice, but you can handle it
<activity android:name=".MyActivity"
android:configChanges="locale"
android:label="#string/app_name">
Then in your Activity
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Do your stuff here
}
Remember to take care of your state. Using setRetainFragment(true) is a good approach. Read this
Yes your code is correct and if you want without refreshing the application
then In Your Application class you need to call this in onCreate() method
String languageSelected = "en";//selected language
Locale myLocale = new Locale(languageSelected);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
getActivity().onConfigurationChanged(conf);//Call this method
You need to perform this particular language to be selected on Application class.

Change language without restarting activity

I have a method that translates my application from English to Swedish and back again if the user so wishes. However, I don't really like the fact that the activity restarts every time because it's giving me a hard time with the savedInstaceState and I've had several crashes because of this.
Here's how my method that changes language looks:
public void setApplicationLanguage(String language) {
myLocale = new Locale(language);
Resources res = activity.getResources();
DisplayMetrics display = res.getDisplayMetrics();
Configuration configuration = res.getConfiguration();
configuration.locale = myLocale;
res.updateConfiguration(configuration, display);
Intent refresh = new Intent(activity, StartupActivity.class);
activity.startActivity(refresh);
}
Is there any chance that the same function can be applied without the:
Intent refresh = new Intent(activity, StartupActivity.class);
activity.startActivity(refresh);
?
Try this
I also had this issue.I used the code below and then it changed the language without refreshing the activity
public void setLocale(String lang) {
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
onConfigurationChanged(conf);
/*Intent refresh = new Intent(this, AndroidLocalize.class);
startActivity(refresh);*/
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// refresh your views here
lblLang.setText(R.string.langselection);
super.onConfigurationChanged(newConfig);
// Checks the active language
if (newConfig.locale == Locale.ENGLISH) {
Toast.makeText(this, "English", Toast.LENGTH_SHORT).show();
} else if (newConfig.locale == Locale.FRENCH){
Toast.makeText(this, "French", Toast.LENGTH_SHORT).show();
}
}
declare in Manifest android:configChanges="locale"
You can replace the code:
Intent refresh = new Intent(activity, StartupActivity.class);
activity.startActivity(refresh);
With the method from Activity class:
recreate();
I hope your minimum SDK version will support because it was introduce in SDK 11. Your activity will be recreate as a new instance remember! Everything will be started afresh. From my experience it is fast compared to making a new Intent. But if you want to pass some data the method of using Intent is better than that! You can add extras to the Intent.
Create a singleton class:
public class Singleton {
private static Singleton mInstance = null;
private int repeat = 0;
public int getRepeat() {
return repeat;
}
public void setRepeat(int repeat) {
this.repeat = repeat;
}
}
Now you have a method that you can set and get the data, so make a method and put it under onResume() method, call your method and you can get and set the data like this:
Singleton.getInstance().setRepeat(1);
Singleton.getInstance().getRepeat();

Language change to arabic not working?

I have implemented change language from settings as per this ans , but after killing of my application some of the screen of application turned to english.
I have implemented code as below
Code for Splash Screen
String deviceLanguage = Locale.getDefault().getLanguage();
if (!"en".equalsIgnoreCase(deviceLanguage) && !"ar".equalsIgnoreCase(deviceLanguage)){
deviceLanguage="en";
}
((AppController)getApplication()).appLang= Utilities.getSaveData(this, getString(R.string.key_language),deviceLanguage);
Code for Detail Activity
#Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MyContextWrapper.wrap(newBase, ((AppController)newBase.getApplicationContext()).appLang));
}
Note : I got this problem in one plus 3T device and genymotion emulator with 5.1 android version
final Resources res = appContext.getResources();
final Configuration conf = res.getConfiguration();
conf.locale = new Locale("ar", "AE");
res.updateConfiguration(conf, null);
After updating configuration, Restart the activity as mentioned below
finish();
final Intent intent = getIntent();
startActivity(intent);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);

Restart a single task activity

I have a singleTask activity and my app supportsRtl, so when I try to change the language, this SingleTask activity is not affected so I need to restart it, Any help?
If you're using API 11 and above you can use the:
Activity.recreate()
If you need to support lower API use this to call your activity again:
Intent i = getIntent();
finish();
startActivity(i);
If we use this approach we don't need to restart the activity
change your app language with the following code:
public static void notifyForLanguageChange(Context context, String languageCode) {
Resources res = context.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale(languageCode.toLowerCase());
res.updateConfiguration(conf, dm);
}
and after that change your screen labels with(i.e reload string resources)
public void setLabels() {
txtFirstView.setText(R.string.first);
txtSecondView.setText(R.string.second);
btnThirdView.setText(R.string.third);
}

How to apply new Locale in Android to current screen

I have implemented an option to select GUI language in my app, but I can't make it refresh the screen when a new language is selected.
The selection is made through a ListPreference so there are 2 problems :
1. Refresh the Preference page in which the language is selected.
2. When the app starts, I set the Locale on the onCreate() of the MainActivity but the MainActivity layout is never getting updated with the new selected Locale. (all other screens are updated so the set code is good).
Here is the code for setting the new Locale :
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
String langKey = ctx.getString(R.string.shared_options_select_language_key);
String langDefault = ctx.getString(R.string.shared_options_select_language_default_value);
String appLanguage = preferences.getString(langKey, langDefault);
Locale locale = null;
if (appLanguage.equals(langDefault)) {
locale = new Locale(Resources.getSystem().getConfiguration().locale.getLanguage());
} else {
String[] languageInfo = appLanguage.split("_");
if (languageInfo.length > 1) {
locale = new Locale(languageInfo[0], languageInfo[1]);
} else {
locale = new Locale(appLanguage);
}
}
if (appLanguage.contains(currentLang)) {
return false;
}
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
act.getBaseContext().getResources().updateConfiguration(config, act.getBaseContext().getResources().getDisplayMetrics());
Thank you
Try to refresh the MainActivity after selecting the new Locale
use this to reload the main activity or any activity
public void refrehs_me()
{
Intent intent = getIntent();
finish();
startActivity(intent);
}
Edit : As I can get from your explanation above you save the new locale selected in a shared preference.
Make a new boolean key in the shared preference called (locale_changed) - when a user select a new locale set this key to (TURE) and on the onCreate after setting the new locale check for this key if (TRUE) set it to (FALSE) and reload the activity.
on the second go it will not loop as the key remains (FALSE) until a user change the locale preference again.
The answer would be to position the call to setLocale right before setting the screen content :
setLocale();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Categories

Resources