when use getDefaultSharedPreferences and getSharedPreferences - android

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

Related

does the context passed on getDefaultSharedPreferences affects the result?

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)

Is there way to use PreferenceActivity without storing values in shared preferences

I have an android application that has uses few serializable classes
(I can store and load them in JSON format using Google Gson library and it works like a charm).
Now I want to provide way for user to edit those objects in fashion similar to PreferenceActivity - they contain few strings, ints and doubles and PreferenceScreen just seems ideal for editing them.
Is there a way to 'abuse' PreferenceActivity to provide UI for editing my objects without actually storing data in shared preferences?
For example - if there was some callback to override that is called just before saving data, I could extract data, assemble my object and somehow prevent Android from messing with preferences?
SharedPreferences is an interface, so you should be able to provide your own implementation that stores data however you like. But the PreferenceManager used by PreferenceFragment only has a setter that takes a file name, not a custom implementation of SharedPreferences.
I looked into the source and found a roundabout way to use your own implementation. PreferenceFragment uses its hosting Activity as the Context for constructing a PreferenceManager. PreferenceManager subsequently calls Context#getSharedPreferences(String, int) to get the SharedPreferences that it will use. Therefore, you can override getSharedPreferences in the activity hosting your PreferenceFragment and return your custom implementation. Implementing SharedPreferences could be rather complicated since you'll also have to implement SharedPreferences.Editor, but it's doable. And if there's any chance of your overridden getSharedPreferences being used anywhere else, you should document that it uses a different backing store.
In the Android O preview, there's a new interface called PreferenceDataStore and a new setter in PreferenceManager that takes an instance of that interface. PreferenceDataStore looks much simpler to implement than SharedPreferences. But as I write this, most retailers are still selling L and M devices, so who knows when we'll see O.
First I would think if I really want to present objects editing with preferences UI since it might confuse a user.
If you still decide to go this way you can achieve it with:
Serialise every object in separate shared preference file and use preference activity how it is designed
Write own PreferenceManager and use reflection to replace private field in PreferenceActivity
The first one is straight forward and rather simple to implement, might have some performance implications. The second one might get tricky and probably requires more code to write.
I would still advice to revise decision to "re-use" PreferenceActivity for such case.

in Android why we have - Context.getSharedPreferences() and -Activity.getPreferences()?

in Android why we have
- Context.getSharedPreferences()
and
-Activity.getPreferences()
but we can change the model in each one between private and multiple so it will be same !! i know there is another function but what is it ?
Always useful to read the documentation first! Furthermore reading the source code really helps a lot at times.
Context.getSharedPreferences(String name, int mode)
This is the main method. What it does is it fetches the contents of preference file "name", stores and returns it via a singleton.
Activity.getPreferences(int mode)
As said, this just calls the above, but with specific name which actually is equal to:
getLocalClassName()
PreferenceManager.getDefaultSharedPreferences(Context)
This also calls Number 1 with the name: getPackageName() + "_preferences";
That said you can also supply the first two methods with ones of these modes:
MODE_PRIVATE
The default mode you should be using (also default for Number 3).
MODE_MULTI_PROCESS
Meant to be used if your application has multiple processes, where a singleton is not enough to keep the preferences up-to-date.
MODE_WORLD_READABLE Deprecated in API 17
MODE_WORLD_WRITEABLE Deprecated in API 17

Migrate from getSharedPreferences(custom file) to getDefaultSharedPreferences()

When I originally wrote and published my app, I was using a custom written activity to handle application settings. I used custom file name to store shared preferfences, like this:
getSharedPreferences("custom_settings_file",MODE_PRIVATE);
But now I'm refactoring my app and I would like to implement PreferenceActivity or PreferenceFragment and an xml file with PreferenceScreen section. Every tutorial or example that I've seen is using
getDefaultSharedPreferences(context);
to retrieve shared preferences, because PreferenceActivity assumes default filename to store preferences and there's no way to tell it to use a different one(at least I couldn't find one after an hour of searching and reading documentation).
So now I have a problem. If I just simply use the new default file, existing users of my app will lose their settings when they update the app, because the new application will not know anything about "custom_settings_file". What would be the best way to move the data from an old file to a new one on app update?
Here are the possible options that I could come up with:
Extend Application class and implement a piece of code in onCreate() so that every time my app is launched, it would check for existence of "custom_settings_file" and move it's contents to the new one. But running a block of code on every app launch seems like wasting too much processing resources for an operation that only needs to run once.
Just notify the user that their old settings are gone. But obviously this is not acceptable.
Is there a better solution, than option 1? Perhaps someone has already faced a similar problem?
What is preventing you from doing number 1 only once?
Just add a "migration" boolean to the new sharedpreferences.
If you also load the xml preference file then you can try this:
PreferenceManager.setDefaultValues(context, YOUR_PREFERENCE_NAME, MODE_PRIVATE, R.xml.preference_file, false);
If not (you want to add each preference item dynamically in your code) then you can do like this:
PreferenceManager pm = getPreferenceManager();
pm.setSharedPreferencesMode(MODE_PRIVATE);
pm.setSharedPreferencesName(YOUR_PREFERENCE_NAME);
In case you still want to use the defaultSharedPreference and process the migration then ... I'm writing this and I see Nicklas's answer, so I'm done here.
Could you add value in your new SharedPreferences that records whether you are a new install or an upgrade. If you don't have the setting in your sharedpreferences, check to see if you have an old preferences file in the way you were before. Then convert those preferences to your new method, and set your private setting indicating that it's been upgraded. Then just set the new value indicating the new state and you won't need to check your old preferences any more.

Dynamic preferences for a variable number of profiles in an Android app

I am looking for a way to create dynamic preferences where I don't need to hard code the preference key and I could have a variable number of preferences.
Basically, my application will let the user create a multiple number of profiles and each of these profiles will save custom values for a fixed number of preferences.
So this way, the user does not have to change the preferences every time he wants this app to run differently, he can just switch the profile.
One way I think will work is by subclassing all the standard Preference classes and calling their setKey method with my custom preference key, containing the profile name, but this is ugly.
So is there a cleaner and more standards compliant way to do this?
Regards,
Dhruwat
You can save different preferences in a different file for each user using the getSharedPreferences method:
getSharedPreferences() - Use this if you need multiple preferences files identified by name, which you specify with the first parameter.
That way, you can do something like this:
SharedPreferences settings = getSharedPreferences("prefs_user_"+user_id, 0);
// from now on you can use use the normal way to set or get the preferences
I'm assuming you are using an id in order to identify them users.

Categories

Resources