Initializing Preferences - android

Android Guide recommends defining preferences in XML files, And from there, these can be loaded in PreferenceActivity/PreferenceFragment etc for viewing and editing by user. But in real scenario, User Interacts with other activities first, then (maybe) with Preferences UI.
What if the starter activity needs some of these preferences ? They'll be not loaded yet, because preferences resources has not been inflated yet. Is there a way to pre-access preferences in XML files ?

Yes. When you first request the preference you can provide it with a default value. E.g. if you are loading a preference of type Int, then you can do so in the following manner from an activity:
SharedPreferences defaultSettings = PreferenceManager.getDefaultSharedPreferences(this);
int preferenceValue = defaultSettings.getInt("PreferenceName", 7);
This would load your preferenceValue to be 7 (without this preference ever being initialized yet). This is assuming that in your XML preference file, you have a preference of key "PreferenceName". If you plan on editing this preference in the activity before the Preference activity has been ran, be sure you commit your changes with a SharedPreferenceEditor:
// ... change to preferenceValue occurs prior to this code
SharedPreferences.Editor defaultEditor = defaultSettings.edit();
defaultEditor.putInt("PreferenceName", preferenceValue);
defaultEditor.commit();
We probably want to avoid "PreferenceName" in a hardcoded matter though, and instead use it as a string in the strings.xml file. This way it can be grabbed both from the initial code when the preference has not been saved yet and from the Preference XML file as well. This means that our above code would substitute the string "PreferenceName" with something like the following:
getResources().getString(R.string.pref_name)
And in your Preference XML file you may would reference the key in the following way:
android:key="#string/pref_name"
android:defaultValue="7"
This should cover "pre-loading" the preference as well as trying to keep most of the application settings within one place. There may indeed be overlap in terms of whether or not the XML preference was created/loaded before the initial Activity occurred, but I haven't tested that out yet.
EDIT: It turns out instead of using the above code, you can directly load the XML file (with its default preference) by the following method:
PreferenceManager.setDefaultValues(this, R.xml.preference, false);
More information about this method can be found in the documentation for the PreferenceManager: http://developer.android.com/reference/android/preference/PreferenceManager.html

If you look at SharedPreference API, you will see this
getString(String key, String defValue)
So, you can actually in fact define a default value if it's not already existed.
Source: http://developer.android.com/reference/android/content/SharedPreferences.html
You can also predefine default value in XML using
android:defaultValue="SOMETHING"

Related

Shared Preferences differences

1) What is the difference between
PreferenceManager.getDefaultSharedPreferences(context)
and
getSharedPreferences(name, mode)
2) And what does each of them do?
3) And how can I make a setting screen (Activity)?
1) You can have multiple SharedPreference files (so they are called SharedPreferences). The argument name of method getSharedPreferences(name, mode) specifies the the name of SharedPreference file to handle.
PreferenceManager.getDefaultSharedPreferences(context) returns the default SharedPreference file having default name and mode. Default name is based on your app's package name (as packagename_preferences.xml) and default mode is MODE_PRIVATE.
If you just want to use a single SharedPreferences file, PreferenceManager.getDefaultSharedPreferences(context) is concise to use.
2) With SharedPreferences you can save some key-value data.
3) Your last question: how to make a setting screen? is too wide topic to answer here. However, I suggest that using PreferenceActivity or PreferenceFragment you can manage a SharedPreferences without handling SharedPreferences directly.

Android: PreferenceManager vs Context.getSharedPreferences() and why the latter failed me

ok, following the Udacity Android Development Course, I reached the part where I'm expected to access the postal code saved to a sharedPreferences file called pref_general.xml, which has the postal code saved in string type and connected to a key called location via key-value pair.
My approach to the problem was to use the getSharedPreferences() method to get the file by name. While that appears to not cause problems because the file didn't turn out null, the attempt to retrieve the postal code resulted in not finding the value via the key and settling on the given default value of the argument.
SharedPreferences appPreferences = getActivity().getSharedPreferences("pref_general", Context.MODE_PRIVATE);
if(appPreferences == null) {
Log.v("ERRORTAG", "Cannot get sharedPreferences file");
}
String getPostal = appPreferences.getString(getString(R.string.pref_location_key), "0");
Log.v("ERRORTAG", getPostal);
The 2nd verbose statement on logcat results in the default String value of 0 instead of the value tied to the given key of 94043 postal code.
Now the answer Udacity gave was to use PreferenceManager, which grabs the default lone sharedPreferences file tied to the Activity
SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
The file isn't null AND the retrieved postal code is the given default postal code 94043 set within the sharedPreference file as a key-value pair.
I want to understand why my approach wasn't working; it was quite close. The only difference was how the file was accessed. Please give me an explanation as to why. Thank you.
The docs for PreferenceActivity say:
If you are using PreferenceActivity in its old mode, the documentation [for PreferenceFragment] applies to the deprecated APIs here.
And the docs for PreferenceFragment explain what's happening:
To retrieve an instance of SharedPreferences that the preference hierarchy in this fragment will use, call getDefaultSharedPreferences(android.content.Context) with a context in the same package as this fragment.
This suggests that PreferenceActivity#addPreferencesFromResource(...) does not create a SharedPreferences file with the same name as the original. Instead, it merges the file into the default shared preferences. The pref_general file does not exist, and you're basically creating it when you attempt to read from it. (Though it's not actually created on disk until you edit it.)

How can I force SharedPreferences to save?

As far as I can tell, values aren't stored in Android's SharedPreferences until they're explicitly accessed. That is, while they may have default values in XML, no value is placed in a SharedPreferences store until an accessor method is called, which is why all the accessors have "default" parameters included.
While this isn't a huge deal for simply pulling values out of the preference store, it prevents any attempt to get all the preference keys that are used in the application, even if they are stored in XML. The keys don't appear when SharedPreferences#getAll() is called unless the preference has already been explicitly accessed.
Is there any way to force all preferences defined in XML to be saved into a SharedPreferences store? The nearest solution I can find is to manually parse the Preference XML files, find all keys and defaults, and save the default value for each one. Is there a cleaner approach?
UPDATE
After looking at this in more depth, I've been getting a partial list of preferences for a different reason. When the defaults are set, only EditTextPreference and ListPreference values are saved. The other two, a custom preference and a CheckBoxPreference, are completely ignored. Here's an example of the CheckBoxPreference that's being ignored:
<CheckBoxPreference
android:defaultValue="false"
android:key="PREF_NAME"
android:summary="Summary text"
android:title="Title" />
Any idea why not all defaults are being set?
You can use PreferenceManager::setDefaultValues. For instance, at your Application::onCreate method.
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
If the last argument is false, this will only set the default values if this method has never been called in the past.
The reason for the missing preferences in my case was actually an Android bug. The workaround was to manually set the missing preferences to their default values, as indicated in a duplicate question: Android CheckBoxPreference Default Value

How to bind the automatic preferences file to the custom preferences in android

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.

Android preferences - Can they be hierarchical?

I can read and write shared preferences and have verified that the resulting XML file looks correct. But is it possible to build a hierarchy of preferences instead of just a flat list?
I'm accessing the preferences directly from my code, so the solution must not assume a preferences screen is present in the app. I have found the PreferenceGroup, PreferenceCategory, and PreferenceManager classes, but they seem to assume a preferences screen is present.
But is it possible to build a hierarchy of preferences instead of just a flat list?
No, sorry. From the rest of your question, it's unclear why you are using SharedPreferences in the first place, instead of another persistent data model (database, XML file, JSON file, etc.)

Categories

Resources