I'm getting an weird error so I'm trying to eliminate the possibilities.
Does the context passed to PreferenceManager.getDefaultSharedPreferences() changes the result?
I mean, when i'm writting setting to my app i never pay attention which context i pass to this method since it is a valid context...
Sometimes i put the Activity, sometimes the Appliaction whatever context i've on hands
Is it wrong? I've noticed that i'm getting wrong preferences values at some point, and i dont know if there is a bug in my code or if this be
It doesn't matter whether you provide an Application or an Activity as the Context parameter for PreferenceManager.getDefaultSharedPreferences().
If you look at the source for getDefaultSharedPreferences():
return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
getDefaultSharedPreferencesMode());
Looking further, into getDefaultSharedPreferencesName(context):
return context.getPackageName() + "_preferences";
This means that for any Context of your application, you'll get the same SharedPreferences back, as your application ID does not change based on Activity or Application.
The only time you could run into a potential issue is if you are manually creating a Context for another package (e.g. using Context.createPackageContext()).
SharedPreferences data stores all have a name, and as long as you use the same name you'll always get the same data store.
Hat tip to #kcoppock who has pointed out that in the particular case of PreferenceManager.getDefaultSharedPreferences(), the only thing the generated name is dependent on is the Context's package. Since any Application or Activity instance you pass is exceedingly likely to have the same package name, in your case you should always get the same data store.
There are other ways to retrieve SharedPreferences stores, though. Activity.getPreferences() will generate the name based on the Activity's class name, so calling getPreferences() from inside two different activities will give you two different data stores.
You can also call Context.getSharedPreferences() directly (both PreferenceManager and Activity just call through to this) and pass a data store name explicitly. There's no requirement for how the name should look; as long as you use the same name you'll always get the same data store.
https://developer.android.com/reference/android/content/Context#getSharedPreferences(java.lang.String,%20int)
Related
How to remember data on android app after app has been closed?(for example: In android calculator, it remembers the numbers from previous calculations,after app has rebooted again)
You can take benefit from SharedPrefrences
more info here : SharedPreferences Docs
I will give you a simple example
let's say we wanna store a String result
we save it in SharedPrefs like this :
PreferenceManager.getDefaultSharedPreferences(this).edit().putString("Result","your value").apply();
Next time in app restart or launch retrieve we like this :
String result = PreferenceManager.getDefaultSharedPreferences(this).getString("Result","defaultValue");
default value is : Values to return if this preference does not exist.
you can change "this" with getActivity() or getApplicationContext() in
some cases
and you can of course change putString and getString with putInteger or putBoolean as you which and get them with getInteger or getfloat etc..
Looking through this tutorial: http://www.newthinktank.com/2013/04/android-user-interface/
The app assigns a string constant for each value to be saved. Then when the savedinstancestate is made, the values are assigned to the keys. And when the savedinstancestate is loaded, they are found using the keys. Why is it necessary to use the constants as the keys? What's wrong with just using s a string as the key like this?
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putDouble("TOTAL_BILL", finalBill);
outState.putDouble("CURRENT_TIP", tipAmount);
outState.putDouble("BILL_WITHOUT_TIP", billBeforeTip);
}
You dont have to use constants if you dont want to, its just a convenience method to not make coding mistakes. Actually with time you will find that you are using a lot of bundles, sharedpreferences and other components requiring use of some string keys. In case of savedinstance handling in activities they are used in single class, but sharedpreferences or using bundles with startActivityForResult thats not the case, such string key constant is used by different classes, sometimes in different packages. Its good practice to manage such constants in some ordered manner. For shared preferences I use separate class called Consts, for startActivityForResult bundle arguments I try to keep keys in Activity beeing called (because it can be called by different activities).
also it makes it easier to prefix such constants with some well know word, ie.: KEY_ , in provided tutorial I would use rather names as KEY_TOTAL_BILL, KEY_CURRENT_TIP, ... This makes it easier to find them using code completion, especially when you have lots of other such fields in class.
If you mistype the key, it could be difficult to find where the error lies. It is much safer to use a constant.
Same goes for storing and retrieving data inside an Intent, you wouldn't want to go through every activity that handles that Intent looking for a mistyped key.
Is there any disadvantage in transferring values from Activity A to Activity B with static fields of a third class instead of the ExtraBundle?
In my application, sometimes I have like 15 - 20 values that I need to transfer between two Activitys. In my oppinion, it is more lucid solving this with static fields from a sort of TransferHandler.
At the moment, I have one disadvantage in mind: When a value is not put into the Extras before starting Activity B, I will get an Exception. Solving it with static fields, it it possible that I forget to assign a value, and if that value was assigned before from somewhere else, it might be that a wrong value is used in Activity B. Nonetheless, I think this is a "programmer problem" and not a "program problem". So are there any further minusses or am I free to choice a way? How's with the performance of the two variants?
First of all, if you plan to use static values, you should use your Application class to do this (because Android system assures you that it is a true singleton)
Thus, you can store your datas in attributes of your custom Application class, and use specific methods to store and get these values.
This will ensure you can't "forget" any values.
Also, with 15-20, I will strongly advice you to make a specialized POJO class to store all this...
I think the biggest disadvantage with using static classes for passing information in android is that static fields and objects can be cleared by the system at any time. That means that any static non final value can ALWAYS be null.
So it will probably work fine most of the time, but if you don't make sure to handle these null situations and your users start using your app they'll get a null pointer exception crash once in a while because the system decided it needed that memory stored in those static fields.
The best way for passing data between activities is by my opinion by using Intents, see here for a good example. Alternatively use a database or the the sharedpreferences.
Google also have a good read about pass data between Activities/Services here.
You cannot use a third class to transferring values form one activity to other. Here is the problem with it. You create one object in the activity-a then you store some values into it. Then after for using the values you need to create one more object in the activity-b then the object created in activity b will not be having the values you assigned in activity-a.
You can use SharedPreferences class to store valuo of variables:
SharedPreferences settings = getSharedPreferences("shared_pref", MODE_WORLD_READABLE);
SharedPreferences.Editor editor = settings.edit();
// With editor you put data
editor.putString(firstName, "John");
editor.putString(lastName, "Smith");
editor.commit();
You can access this data in all activities:
// With settings you access to data in different activities
SharedPreferences settings = getSharedPreferences("shared_pref", MODE_WORLD_READABLE);
String firstName = settings.getString(firstName, null);
String lastName = settings.getString(lastName, null);
I just curious. There are 3 method:
1. getPreferenceManager().setSharedPreferencesName(String PrefName);
2. PreferenceManager.getDefaultSharedPreferences(Context context)
3. Context.getSharedPreferences (String name, int mode)
As I know, the third method is only used when the first method is used, right?
But with 3 method we also use addPreferencesFromResource(int resID);
so, what is the difference? When can we use one of these method?
Thanks!
Let's go one step at a time:
setSharedPreferencesName() is method that allows to set the name of the preference group for later use. This is helpful for example when using the helper class of
PreferencesActivity before loading a preferences from XML resource file by calling addPreferencesFromResource(). It is therefore not as common as the other 2 methods you mentioned above.
getDefaultSharedPreferences() uses a default name, usually stored as /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml.
It is commonly used. Note that this default is set per application.
The alternative method - getSharedPreferences() requires to indicate a specific preference (file) name and an operation mode.
As appears also in another answer about shared preferences,
getDefaultSharedPreferences() in fact uses Context.getSharedPreferences, so the result is the same, but without the flexbility to split to multiple preference files, that is offered by getSharedPreferences(). Sharing the preferences between apps using
a MODE_WORLD_READABLE operation indicator is also something possible using getSharedPreferences(), but is rarely used.
IMHO, getDefaultSharedPreferences() can be safely used without going into the confusion of multiple preference file names that are prone to typos and confusion.
If someone knows of a good reason to use getSharedPreferences() and not getDefaultSharedPreferences(), please let me know by commenting here.
getDefaultSharedPreferences() uses a default preference-file name like "com.example.something_preferences". This default is set per application, so all activities in the same app context can access it easily as in the following example:
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
if (spref.contains("email")) {
String sEmailAddr = spref.getString("email", "");
}
The preferences are usually stored at /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml
getSharedPreference is the best way because using getDefaultSharedPreferences has some flaws
Actualy getDefaultSharedPreferences doesn't work correct on some
devices when build with targer api 13
Starting app from shortcut and from menu gives me different
DefaultSharedPreferences. After removing DefaultSharedPreferences
from my code - it works perfect. I can't just say: people dont make
shrotcuts, so I had to change code
This link may also help
I have an application which has some static variables.
These variables are stored in an independent Class named DataContext.
These variables are initialized from raw files at the application start (a method named DataContext.initConstant() is called in the onCreate() of MyApplication which extends Application).
(EDIT : the initConstant method use an AsyncTask to load this data from files).
When my application comes to the background for a certain time or when my application used to much memory, these static variables become null.
How can it be prevented?
If not what should I do with my static variables?
I have other data which are stored in static variables to be used across different activities, but I clear them or pass them to null in the onLowMemory() of MyApplication.
What is the best way to keep some data accessible between activities if these data are too big to be serialized in an Intent, a database can't be used (for whatever reason), and can't be stored in files through serialization either?
You can't. Android needs to free up memory from time to time. Imagine if all applications had a ton of static data that is supposed to be resident forever - how would you fit that in memory? It's a mobile phone. It doesn't have virtual memory.
(and 3): Anything that is intended to be persistent needs to be stored, either via SharedPreferences, a Sqlite database, or a file.
Most likely the issue is that your application is being killed while it is in the background, and then recreated when you come back to it. Check out the Activity Lifecycle documentation on when this might occur for a single activity. You need to make sure that you move anything stored in memory to more permanent storage at the correct point in time to avoid losing that information if the app gets killed.
I'm not sure what exactly you are storing, but it sounds like using Shared Preferences might work well. This page on Data Storage explains a number of different ways of more permanently storing data, including Shared Preferences.
If you weren't using raw files, I'd advise initializing when the class is loaded.
For instance,
public static Map<?,?> myStaticMap = new HashMap<?,?>();
static { //fill myStaticMap }
You do have some bigger concerns to worry about if you are loading files that way. For instance, what about I/O errors, or latency issues? You will get warnings in gingerbread (if you enable them) for doing I/O in your main thread. Perhaps you should have an object to retrieve these values instead of a class with static fields. (perhaps with a static cache, although you should synchronize on it before checking/changing it)
I assume this is a data cache problem.
Storing data in static class is not guaranteed to work when user swap apps often. Android system will reclaim any background activity when memory is low. Static class is definitely among this category.
The proper way to do it is to use sharedPreference to persist cache data.
You can create your own getter and setter of the data you want and wrap it around sharedPreference object. When you access using getter, you should always check if the value is empty or expired. You can store an update_time when using setter.
For activity specific data, you can just use getPreference(permission), if you want to share data across activities and other applications components, you can use getSharedPreference(name, permission).
Normally, the permission will be MODE_PRIVATE such that the data can only be accessed within your application.
You should group data and store in difference sharedPreference object. This is good practice because when you want to invalidate that group of data, it is just a matter of one liner.
editor.clear(); editor.commit()
If you want to cache complex object, you should serialize it. I prefer JSON format. So you need some conversion mechanism in place. To do this, I will create my data object class extending JSONable class. JSONable class will have toJSON() method and readFromJSON(). This is convenient when restore and serialize data.
I store a User object and a Client object in my static scope. I have noticed from time to time the reference becomes null. So now in my getters I check to see if this value is null and if so I restart the app.
Intent i = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(i);
I could have also chosen to reload the Client because I store the Access Token in prefs however I do so much initialization that I decided restarting the app would the best idea.
In your onResume() method you could query the static data to see if it is present and if not, load it back in again.
Instead of using the static variable u can use the shared preference for storing the value.
Note: for shared preference also you should not give heavy load.
I have solved this problem by having the super class with getter and setter function for storing and retrieving shared preference variable.
All class in my application extended the super class instead of activity.