I have been wondering for a while why my onCreate method is run twice and have now found out that it has to do with me setting the locale of the app at launch... My question is, is it necessary for it to run twice or not?
This is the code that makes onCreate run twice:
/*Sets the language of the application and also returns the integer value of selected language*/
protected Integer setLanguage() {
String lang = prefs.getString("language-key","0");
Integer language = Integer.parseInt(lang);
Configuration config = context.getResources().getConfiguration();
if (!decideLang(language).equals("") && !config.locale.getLanguage().equals(decideLang(language))) {
setLocale(decideLang(language));
}
return language;
}
/*Sets the locale*/
private void setLocale(String lang) {
((Activity) context).recreate();
Locale myLocale = new Locale(lang);
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
}
The integer that the setLanguage method returns is later used to determine what URL to use in a later stage but I have come to realize that is not important for my question.
My question is, WHY does onCreate need to run twice because of this code?
((Activity) context).recreate();, as it states on the tin, recreates the Activity, so onCreate() is, of course, going to be called twice.
(From comments)
Related
I want to change the language of the app and this works fine until API 26.
For api > 25 I put Locale.setDefault(Locale.Category.DISPLAY, mynewlanglocale); before setContentView(R.layout.activity_main); but nothing changes.
The docs don't explain too much about this.
I had the same problem: since Android 8.0+ some parts of my app did't change their language anymore. Updating of both application and activity context helps me. Here is an example of MainActivity function:
private void setApplicationLanguage(String newLanguage) {
Resources activityRes = getResources();
Configuration activityConf = activityRes.getConfiguration();
Locale newLocale = new Locale(newLanguage);
activityConf.setLocale(newLocale);
activityRes.updateConfiguration(activityConf, activityRes.getDisplayMetrics());
Resources applicationRes = getApplicationContext().getResources();
Configuration applicationConf = applicationRes.getConfiguration();
applicationConf.setLocale(newLocale);
applicationRes.updateConfiguration(applicationConf,
applicationRes.getDisplayMetrics());
}
Yes in android Oreo localization is not working fine with updateconfiguration. But it is deprecated in android N itself. Instead of updateconfiguration use createconfiguration in each attachcontext. it is working fine for me. Try this...
In you activity add this..
#Override
protected void attachBaseContext(Context newBase) {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
super.attachBaseContext(MyContextWrapper.wrap(newBase, "ta"));
}
else {
super.attachBaseContext(newBase);
}
}
In MyContextWrapper.java
public static ContextWrapper wrap(Context context, String language) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
Locale newLocale = new Locale(language);
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 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new ContextWrapper(context);
}
updateConfiguration is deprecated and you should use createConfigurationContext. I solved it this way:
#Override
protected void attachBaseContext(Context newBase) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Configuration config = newBase.getResources().getConfiguration();
//Update your config with the Locale i. e. saved in SharedPreferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase);
String language = prefs.getString(SP_KEY_LANGUAGE, "en_US");
Locale.setDefault(locale);
config.setLocale(new Locale(language));
newBase = newBase.createConfigurationContext(config);
}
super.attachBaseContext(newBase);
}
Updated For All android versions till Oreo
Create a class like this
public class LocaleUtils {
#Retention(RetentionPolicy.SOURCE)
#StringDef({ENGLISH, FRENCH, SPANISH})
public #interface LocaleDef {
String[] SUPPORTED_LOCALES = {ENGLISH, FRENCH, SPANISH};
}
public static final String ENGLISH = "en";
public static final String FRENCH = "fr";
public static final String SPANISH = "es";
public static void initialize(Context context) {
setLocale(context, ENGLISH);
}
public static void initialize(Context context, #LocaleDef String defaultLanguage) {
setLocale(context, defaultLanguage);
}
public static boolean setLocale(Context context, #LocaleDef String language) {
return updateResources(context, language);
}
private static boolean updateResources(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
context.createConfigurationContext(configuration);
configuration.locale = locale;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return true;
}
}
Now when you select the language from your app, Save the language code in Shared Preference like below
private static SharedPreferences getDefaultSharedPreference(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext()) != null)
return PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext());
else
return null;
}
public static void setSelectedLanguageId(String id){
final SharedPreferences prefs = getDefaultSharedPreference(Application.getInstance().getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString("app_language_id", id);
editor.apply();
}
public static String getSelectedLanguageId(){
return getDefaultSharedPreference(Application.getInstance().getApplicationContext())
.getString("app_language_id", "en");
}
These three functions should be written inside a Utiltiy class(your preference). Then when you select the app language from the app, call the setSelectedLanguageId() function and pass the language id as parameter.
This way you have saved the selected language in your app. Now in your application class write a function like this
public void initAppLanguage(Context context){
LocaleUtils.initialize(context, PreferenceUtil.getSelectedLanguageId() );
}
Here the PreferenceUtil is my Utiltiy class. You should replace it with your utility class function.
You should also create a variable in your application class
private static Application applicationInstance;
and in your Application class's onCreate method, initialise applicationInstance to be the applications context like this
applicationInstance = this;
Now write a getter function in your application class
public static synchronized Application getInstance() {
return applicationInstance;
}
And now when you start your first activity, call this method in your activity's onCreate
Application.getInstance().initAppLanguage(this);
Remember that we are passing the activity's context to the initAppLanguage() function, not the application context. Passing the Application context won't make it work in Oreo(atleast for me).
So when you select the language try to restart your application completely.
You can acheive this by
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
startActivity(i);
Hope this helps you!
It is possible, however i would not recommend to set the language programatically
Android is designed so the System UI and your App have the same language, if you change it programmatically you would be fighting the system
Instead what you can do is enable multilanguage support by adding different strings.xml languages, this will change the language automatically
I reccommend reading through this Google Developers article:
Supporting Different Languages and Cultures
If you really need to change it programatically you can do the following
Locale locale = new Locale("en");
Locale.setDefault(locale);
Configuration config = context.getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
On SDK >= 21, you need to call 'Resources.updateConfiguration()', otherwise resources will not be updated.
Hope it helps.
Here is complete solution worked for kitkat, Lollipop, Marshmallow, Nougat and Oreo too. Just follow all below step.
First create a java class like below
import android.content.Context;
import android.content.res.Configuration;
import java.util.Locale;
public class LocaleUtils {
public static void updateConfig(Context mContext, String sLocale) {
Locale locale = new Locale(sLocale);
Locale.setDefault(locale);
Configuration config = mContext.getResources().getConfiguration();
config.locale = locale;
mContext.getResources().updateConfiguration(config,
mContext.getResources().getDisplayMetrics());
}
}
Now add this snippet on Button click where you want to change locale
String lang="hi";//pass your language here
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = preferences.edit();
editor.clear();
editor.putString("lang", lang");
editor.putBoolean("langSelected", true);
editor.apply();
LocaleUtils.updateConfig(mContext,lang);
Intent intent = mContext.getIntent();
mContext.overridePendingTransition(0, 0);
mContext.finish();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.overridePendingTransition(0, 0);
mContext.startActivity(intent);
Finally paste the below code in Splash Activity or in Launching Activity.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String lang = preferences.getString("lang", "");
boolean langSelected = preferences.getBoolean("langSelected", false);
SharedPreferences.Editor editor = preferences.edit();
if (langSelected) {
editor.clear();
editor.putString("lang", lang);
editor.putBoolean("langSelected", true);
editor.apply();
LocaleUtils.updateConfig(this,lang);
} else {
LocaleUtils.updateConfig(this, Locale.getDefault().getLanguage());
editor.clear();
editor.putString("lang", Locale.getDefault().getLanguage());
editor.putBoolean("langSelected", false);
editor.apply();
}
After use all solution in all sources finally i found my issue. That makes me angry for 2 days.
Everyone knows that in Android Oreo (API 26) we must use createConfigurationContext, But My problem is using Country name with local.
Replace
en_US with en
ar_AE with ar
fa_IR with fa
And my problem solved.
Hope to help someone
You need to use getApplicationContext() instead of getContext()
I have to do this:
user should be able to enter text to create post - "create a post " button
these post should be viewed in a wall.
Based on chosen languages, static contents as well as dynamic contents on the app should change accordingly. It should be available in the settings screen of the app.
I have a problem that how to change the language of the content view on MainActivity
You can change static content like this.
First create string file based on the language.
when change language execute this method
public void changeLang(String lang)
{
myLocale = new Locale(lang);
saveLocale(lang);
Locale.setDefault(myLocale);
android.content.res.Configuration config = new android.content.res.Configuration();
config.locale = myLocale;
getActivity().getApplicationContext().getResources().updateConfiguration(config, null);
//getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
updateTexts();
}
private void updateTexts()
{
//update text of label in here.
textLabel.setText(R.string.welcome);
}
next overide the configuration change method
#Override
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (myLocale != null){
newConfig.locale = myLocale;
Locale.setDefault(myLocale);
getActivity().getBaseContext().getResources().updateConfiguration(newConfig, getActivity().getBaseContext().getResources().getDisplayMetrics());
}
}
I have no idea about dynamic content. I think it will not be possible. But if you have content with other langage you can load that when change language.
I'll apologize in advance for posting alot of code, this issue has really got me!
I have two Android JUnit tests that are causing me problems. Run each individually and they work fine, but when run together in one go (PasswordEntryActivityTests and then CryptoKeystoreTests) CryptoKeystoreTests hangs indefinitely.
I know it's not just the emulator being slow because each individually finishes in less than a second but it can hang for more than 20 minutes. I also tested it on a real device (Droid Razr) and it does the same thing.
The problematic code is the PasswordEntryActivity.launchNewPasswordActivity(). Removing that function makes everything work fine.
Pausing the function in the debugger while it's hanging says it's in:
MessageQueue.nativePollOnce(int, int) line: not available [native method]
What's going on?
I've copied below:
PasswordEntryActivity
PasswordEntryActivityTests
CryptoManagerKeystoreTests
Please let me know to post any other code you'd like to see.
Thanks!
public class PasswordEntryActivity extends Activity
{
...
private void launchNewPasswordActivity()
{
Intent launchNewPasswordIntent = new Intent(this, NewPasswordActivity.class);
startActivity(launchNewPasswordIntent);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.password_entry_layout);
...
//this code should be LAST in onCreate because it exits the Activity
//CryptoManager.passwordIsRight returns 0 if no password has been set
passwordExists = CryptoManager.passwordIsRight("x", this) != 0;
if(!passwordExists)
launchNewPasswordActivity();
}
}
That Activity's test:
//supposed to make sure the application responds correctly when no password is set
public class PasswordEntryActivityTests extends android.test.ActivityInstrumentationTestCase2< crypnote.controller.main.PasswordEntryActivity>{
protected void setUp() throws Exception
{
passwordEntryActivity = getActivity();
//delete the database if it exists
File file = passwordEntryActivity.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = passwordEntryActivity.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
}
//allows us to access the interface
#UiThreadTest
public void testNoPassword() throws Exception
{
passwordEntryActivity = getActivity();
EditText passwordEntryEditText =
(EditText) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_passwordedittext);
Button unlockButton = (Button) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_unlockbutton);
int passwordResult = CryptoManager.passwordIsRight("x", getActivity());
assertTrue(passwordResult == 0);
//pass a wrong password to the edittext and click the unlock button
passwordEntryEditText.setText("x");
assertTrue(unlockButton.performClick());
//get the foreground activity class name
ActivityManager am = (ActivityManager) passwordEntryActivity.
getSystemService(Context.ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
String foregroundClassName = componentInfo.getShortClassName();
//don't forget the leading '.'
assertTrue(!foregroundClassName.equals(".PasswordEntryActivity"));
}
}
The CryptoKeystoreTests:
public class CryptoKeystoreTests extends android.test.ActivityInstrumentationTestCase2<
crypnote.controller.main.PasswordEntryActivity>
{
public void testKeystore() throws Exception
{
Context context = getActivity();
//delete the database if it exists
File file = context.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = context.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
CryptoManager cryptoManager=null;
String password = CryptoManager.Constants.DEBUG_PASSWORD;
FileInputStream fis=null;
//the cryptomanager will generate a new key and keystore
cryptoManager = new CryptoManager(password, context);
Key CRYPTOKEY = cryptoManager.getKey();
cryptoManager.close();
//initialize KeyStore
KeyStore keystore = KeyStore.getInstance(Constants.KEYSTORE_INSTANCE_TYPE);
fis = context.openFileInput(CryptoManager.Constants.KEYSTORE_PATH);
keystore.load(fis, password.toCharArray());
assertTrue(keystore.containsAlias(Constants.APP_ALIAS));
assertTrue(keystore.isKeyEntry(Constants.APP_ALIAS));
Key key = keystore.getKey(CryptoManager.Constants.APP_ALIAS,
password.toCharArray());
assertTrue(key.getAlgorithm().equals(CryptoManager.Constants.PROVIDER_NAME));
assertTrue(key.getAlgorithm().equals(CRYPTOKEY.getAlgorithm()));
assertTrue(key.getFormat().equals(CRYPTOKEY.getFormat()));
if(fis != null)
fis.close();
}
}
EDIT: NewPasswordActivity.onCreate:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.new_password_layout);
}
It hangs because PasswordEntryActivityTests does not release/finish the resources/UI events that has been addressed/created by itself during its own running lifecycle, more specifically, then newly opened NewPasswordActivity.
PasswordEntryActivityTests starts by testing a creation of PasswordEntryActivity, i.e. getActivity(), which in consequence, based on the condition, launch a second NewPasswordActivity, the newly opened NewPasswordActivity occupy the foreground window and stay forever, it is developer's responsibility to release it properly after you have done your testing.
In instrumentation test, the correct way of detecting/monitoring second activity startup from current activity is to use ActivityMonitor, see the pseudo code below:
// No password result starting a second activity.
public void testNoPassword() {
// register NewPasswordActivity that need to be monitored.
ActivityMonitor activityMonitor = getInstrumentation().addMonitor(NewPasswordActivity.class.getName(), null, false);
// Get current activity, it will start NewPasswordActivity in consequence.
PasswordEntryActivity currentActivity = getActivity();
NewPasswordActivity nextActivity = getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
// NewPasswordActivity is opened and captured.
assertNotNull(nextActivity);
// Don't forget to release/finish NewPasswordActivity after test finish.
nextActivity.finish();
}
Good morning,
We have developed an android app, and I have been charged with finding out how to remove the undesired behavior of a notification sound every time that the screen orientation changes. Obviously this behavior only exists on devices running OS version 3.2.3 or later.
I have read several posts that indicate that this can be turned off by unchecking USB Debugging in the Settings --> Developer options, however this option is not checked and none of the other apps that are on any of our Android devices make this notification sound upon orientation change.
The application does require there to be a notification when a "message is received" (the app connects to a webservice and gets new messages from the service every so often). So this would rule out any solution that disabled notifications.
Thus far, I have tried several potential solutions:
1) When a message is received, instantiate a new NotificationManager, and after the notification is sounded, destroy the NotificationManager.
if(MessageReceived == true) {
String ns = Context.NOTIFICATION_SERVICE;
messageNotifyManager = (NotificationManager) getSystemService(ns);
}
showNotification();
messageNotifyManager = null;
2) I realize that an orientation change is essentially the view being destroyed and re-created. I put set a flag in the initial onCreate method and checked to see if that flag had value before recreating the Notification Manager.
public static int Flag = 0;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Flag == 0) {
String ns = Context.NOTIFICATION_SERVICE;
messageNotifyManager = (NotificationManager) getSystemService(ns);
Flag = 1;
}
}
3) In the application's main class, I created a public OrientationEventListener property and then set its value in the onCreate method, disabling it immediately. When that didn't disable the sound I tried disabling the property in every class that referenced the application's main class.
public OrientationEventListender listener;
#Override
public void onCreate() {
super.onCreate();
appContext = getApplicationContext();
GetPreferences();
//...
listener = new OrientationEventListener(appContext){
public void onOrientationChanged(int Orientation){
}
};
listener.disable();
}
Now, as you can probably tell, I am very new to Android development. I assume that this solution is something so simple that everyone knows, and that is why there are no answers anywhere handy on the web. But any help with this simple problem would be greatly appreciated. Thanks!
This issue was solved by modifying the AndroidManifest, adding the following tag to each activity: android:configChanges="orientation"
when testing an activity in my app I see that it's not using the values I've set using the PreferenceActivity.
I can confirm that the values are corretly set in the PrefsActivity (at least "locally"), because every time I open it, the settings are exactly like they were when I closed it the last time...
Do I have to specify in my PreferenceActivity which preference file to store the settings into, or is it a problem with the methods I'm using to import those values for use in my activity?
It feels like I've searched all over the web without ever finding a clear answer to that question...
This is where my activity is supposed to load the preferences, does it look right?
I know that's the only thing missing, because the calculation works just fine when I run it in debug mode and manually input the values to use...
public void OnStart() {
// Loads the values for the calculator to use
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
bodymass = settings.getInt(getString(R.string.pref_key_user_mass).toString(), 0);
gender = settings.getString(getString(R.string.pref_key_user_gender).toString(), "");
Also, does this following code look right to you?
(I would also be grateful if someone told me how to make an 'if' statement comparing several variables at once - e.g. if (one out of three fields are empty) {do something})
//Checks defined user gender and sets value to be used by calc accordingly
if (gender == "male") {
genderValue = 0.7;
}
else if (gender == "female") {
genderValue = 0.6;
}
else if (gender == "") {
settingsAlert();
}
It never seems to trigger the settingsAlert()-function, even when all app data is wiped (it should then spawn an alert message, prompting the user to go set the preferences before using, but nothing happens)
Here's the code that's supposed to spawn the alert:
public void settingsAlert() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("#string/dialog_setPrefs_text")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent gotoSettings = new Intent(ActivityCalc.this, ActivitySettings.class);
startActivity(gotoSettings);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
})
.create();
}
--UPDATE--
I have now managed to get the alert dialog spawn like it should, I figured I'd post the code lines that made it happen, so others with the same problem can watch and learn... :)
The problem appeared to be that the alert was indeed created correctly, but never actually called to display - therefore everything worked perfectly once I added that little .show() after the .create() in the last line.
Alternatively, you can define it as an AlertDialog object, and just call it whenever you feel like it:
AlertDialog alert = builder.create();
alert.show();
I'm posting the contents of my PreferenceActivity class here for you to see
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This line will import the preferences to display in the settings activity
addPreferencesFromResource(R.xml.settings);
}
To see how to build the preference resource file, look at this article
I've no longer included the string for specifying the name of the shared prefs to use, as I changed the get-method to use DefaultSharedPreferences instead:
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
I have now only defined and initialized the variables required to be persistent for the rest of the activity:
private double genderValue = 0;
private String gender = "";
private int bodymass = 0;
The app now works exactly like it should - not crashing, and correctly loading the preferences as set in the PreferenceActivity.
You need to use equals for the IF-ELSE sentences
if (gender.equals("male")) { //equals
genderValue = 0.7;
}
else if (gender.equalsIgnoreCase("female")) { //Here the equalsIgnorecase one
genderValue = 0.6;
}
else if (gender == "") {
settingsAlert();
} else {
settingsAlert(); //Probably it always comes here.
}
Another thing.. did you saved the preferences correctly with 'commit' ?
settings.edit().putString(getString(R.string.pref_key_user_gender).toString(), gender).commit();
--After 3rd comment---
Never tried. One for each works fine. But if you check 'duanhong169' comment, there're 2 following putString and the last commited, so.. make a try :)
Anyway you can just do:
SharedPreferences.Editor editor = settings.edit();
editor.putString("gender", genderValue);
editor.putInt("bodymass", bodymassValue);
editor.commit();
And answering your other question.. you need the 'edit' to save a prefference, is how it works. you can use it at onpause, onrestart, or just after you've the data you need (inside a method).
Ie if you need a login data, once after you checked the login is correct, and if you've a different login-pass value stored (different user), you can edit.putString to save the new value inside onResult confirmation.
The better thing you can do is try different methods of saving to prefferences with different tags and then creare a Log and do getString() from each tag, so you'll know which one works, and then you can choose the better/easier for your case.
-- UPDATE 2 --
As far as I know.. (i've never tried that, and like you, i'm really new in android) your preferences.xml should be placed at res/xml and then:
public class PreferencesFromXml extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
and to get the data:
PreferenceManager.setDefaultValues(this, R.xml.prefer, false);
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this);
p.getString("key", "value_default")