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.
Related
My app have had many releases and some of the earlier version sharedPreferences are useless.
What would be the best way to have the app itself sorting out the one that are still used and remove the unused one ?
Basically it would be like parsing the preferences XML's to extract the current android::key and by getting all preferences present on the device remove the one not being anymore in an XML.
Not sure I am very clear, but I have lot's of shared preferences not used anymore and having to establish the list manually can be source of problem.
Any hint would be great,
Thanks a lot
you can go through the keys one by one removing any that you dont use anymore like this
Map<String,?> prefs = pref.getAll();
for(Map.Entry<String,?> prefToReset : prefs.entrySet()){
if(prefToReset.getKey().equals("someKey")){
pref.edit().remove(prefToReset.getKey()).commit();
}
}
though there really is no performance benefit from doing this really
I am new to Android app development and would like a little information on global variables. I have done a lot of searching and I understand that in the class files you can declare a global variable(correct me if I'm wrong). I have taken a look at a lot of posts including Android - Global variables? . They have not helped me to understand what I would like to know. My goal is to be able to create variables that will change and remain changed after the app has been terminated. The idea that I have is that I would like to have a main page that then branches to a bunch of other pages and have a global variable that saves what page your are currently visiting so that when you resume you can press a button labeled continue and it will bring you back to the page that you were previously on. If there is a better way than global variables, I am open to alternatives, thanks in advance!
You can use SharedPreferences to do that. In your activity, use:
SharedPreferences preferences = this.getSharedPreferences("name", Context.MODE_PRIVATE);
preferences.edit().putString("lastPage","mainPage").commit;
To read your saved data, use:
String lastPage = preferences.getString("lastPage");
Read http://developer.android.com/reference/android/content/SharedPreferences.Editor.html to know the types that you can store.
You can't have variables - global or otherwise - persist after the app has been terminated unless you write them to a permanent storage. In Android this can be done with an ObjectOutputStream to write an object to the filesystem or SharedPreferences, which save key/value pairs for retrieval. You will have to save and set your variables when you need them.
But you shouldn't do global variables anyway.
I just implemented a preferences screen for one of the sample apps that I am creating. I followed the guide given on google site. All is fine and I loaded up a ListPreference and I am able to store it and persist it also. There is also one minor problem here. I have already defined a custom preference file for the app but this automatic handling of the preference screeen seems to be creating a preference file on its own. For now I was trying to get this code to work but it is not getting the custom preference file.
final Preference customPrefs = getPreferenceScreen().findPreference(Utils.PREFS_NAME);
customPrefs.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
customPrefs.getEditor().commit();
return true;
}
});
Is there a way to bind the custom preference file with this auto preference class in anyway ?
You can set a custom name for the file used to store the preferences, used in your PreferenceActivity, by calling its getPreferenceManager().setSharedPreferencesName("file_name") method. Just remember that you need to set that before calling addPreferencesFromResource, otherwise your UI will still change stuff back to the wrong file (the default one).
As I said, you don't need to do that, since you can use the default file provided by the system. If/when you need to read the preferences elsewhere, you can then just call PreferenceManager.getDefaultSharedPreferences(Context context).
I already addressed those remarks in another question.
Also remember that some of the methods are deprecated. If you're writing new code, try to avoid them and conform to the new "Fragment Way" of doing things.
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
My application is used on multiple platforms so it saves it preferences to a file (rather than to the standard Android SharedPreferences).
Is there any easy of reusing the PreferenceActivity to save preferences to a file or is it a case of creating a whole new activity to do the job? If the latter is the case is there a layout I can use that will make the activity look like the normal preferences screen? PreferenceActivity uses com.android.internal.R.layout.preference_list_content but this doesn't appear to be available to apps for reuse.
Is there any easy of reusing the
PreferenceActivity to save preferences
to a file or is it a case of creating
a whole new activity to do the job?
Not really. I mean, you could subclass SharedPreferences, rip the guts out, and map it to your own data model, but that would be far, far worse for maintainability than just using SharedPreferences in the first place.
If the latter is the case is there a
layout I can use that will make the
activity look like the normal
preferences screen?
It's just a ListView. It will take you a lot more time to do this than to just use SharedPreferences.
PreferenceActivity uses
com.android.internal.R.layout.preference_list_content
but this doesn't appear to be
available to apps for reuse.
Sure it is. If you have the SDK installed, it's on your hard drive right now. Look in $ANDROID_HOME/platforms/$API/data/res/layout, where $ANDROID_HOME is where you have the SDK and $API is some API (e.g., android-2.1).
You can create a function that exports the data from SharedPreferences to a file.
Normally Preferences are saved into sharedpreferences when the user clicks on the prefrence item. Add your code to update your external dataholder on onPreferenceTreeClick() function.