标签:
The Android framework includes a variety of Preference
subclasses that allow you to build a UI for several different types of settings. However, you might discover a setting you need for which there’s no built-in solution, such as a number picker or date picker. In such a case, you’ll need to create a custom preference by extending the Preference
class or one of the other subclasses.
When you extend the Preference
class, there are a few important things you need to do:
Preference
with the current (or default) value when it comes into view.Preference
provides its own UI (such as a dialog), save and restore the state to handle lifecycle changes (such as when the user rotates the screen).The following sections describe how to accomplish each of these tasks.
If you directly extend the Preference
class, you need to implement onClick()
to define the action that occurs when the user selects the item. However, most custom settings extend DialogPreference
to show a dialog, which simplifies the procedure. When you extend DialogPreference
, you must callsetDialogLayoutResourcs()
during in the class constructor to specify the layout for the dialog.
For example, here‘s the constructor for a custom DialogPreference
that declares the layout and specifies the text for the default positive and negative dialog buttons:
public class NumberPickerPreference extends DialogPreference { public NumberPickerPreference(Context context, AttributeSet attrs) { super(context, attrs); setDialogLayoutResource(R.layout.numberpicker_dialog); setPositiveButtonText(android.R.string.ok); setNegativeButtonText(android.R.string.cancel); setDialogIcon(null); } ... }
You can save a value for the setting at any time by calling one of the Preference
class‘s persist*()
methods, such as persistInt()
if the setting‘s value is an integer or persistBoolean()
to save a boolean.
Note: Each Preference
can save only one data type, so you must use the persist*()
method appropriate for the data type used by your custom Preference
.
When you choose to persist the setting can depend on which Preference
class you extend. If you extendDialogPreference
, then you should persist the value only when the dialog closes due to a positive result (the user selects the "OK" button).
When a DialogPreference
closes, the system calls the onDialogClosed()
method. The method includes a boolean argument that specifies whether the user result is "positive"—if the value is true
, then the user selected the positive button and you should save the new value. For example:
@Override protected void onDialogClosed(boolean positiveResult) { // When the user selects "OK", persist the new value if (positiveResult) { persistInt(mNewValue); } }
In this example, mNewValue
is a class member that holds the setting‘s current value. Calling persistInt()
saves the value to the SharedPreferences
file (automatically using the key that‘s specified in the XML file for this Preference
).
When the system adds your Preference
to the screen, it calls onSetInitialValue()
to notify you whether the setting has a persisted value. If there is no persisted value, this call provides you the default value.
The onSetInitialValue()
method passes a boolean, restorePersistedValue
, to indicate whether a value has already been persisted for the setting. If it is true
, then you should retrieve the persisted value by calling one of the Preference
class‘s getPersisted*()
methods, such as getPersistedInt()
for an integer value. You‘ll usually want to retrieve the persisted value so you can properly update the UI to reflect the previously saved value.
If restorePersistedValue
is false
, then you should use the default value that is passed in the second argument.
@Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { if (restorePersistedValue) { // Restore existing state mCurrentValue = this.getPersistedInt(DEFAULT_VALUE); } else { // Set default state from the XML attribute mCurrentValue = (Integer) defaultValue; persistInt(mCurrentValue); } }
Each getPersisted*()
method takes an argument that specifies the default value to use in case there is actually no persisted value or the key does not exist. In the example above, a local constant is used to specify the default value in case getPersistedInt()
can‘t return a persisted value.
Caution: You cannot use the defaultValue
as the default value in the getPersisted*()
method, because its value is always null when restorePersistedValue
is true
.
If the instance of your Preference
class specifies a default value (with the android:defaultValue
attribute), then the system calls onGetDefaultValue()
when it instantiates the object in order to retrieve the value. You must implement this method in order for the system to save the default value in the SharedPreferences
. For example:
@Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getInteger(index, DEFAULT_VALUE); }
The method arguments provide everything you need: the array of attributes and the index position of theandroid:defaultValue
, which you must retrieve. The reason you must implement this method to extract the default value from the attribute is because you must specify a local default value for the attribute in case the value is undefined.
Just like a View
in a layout, your Preference
subclass is responsible for saving and restoring its state in case the activity or fragment is restarted (such as when the user rotates the screen). To properly save and restore the state of your Preference
class, you must implement the lifecycle callback methods onSaveInstanceState()
and onRestoreInstanceState()
.
The state of your Preference
is defined by an object that implements the Parcelable
interface. The Android framework provides such an object for you as a starting point to define your state object: thePreference.BaseSavedState
class.
To define how your Preference
class saves its state, you should extend the Preference.BaseSavedState
class. You need to override just a few methods and define the CREATOR
object.
For most apps, you can copy the following implementation and simply change the lines that handle the value
if your Preference
subclass saves a data type other than an integer.
private static class SavedState extends BaseSavedState { // Member that holds the setting‘s value // Change this data type to match the type saved by your Preference int value; public SavedState(Parcelable superState) { super(superState); } public SavedState(Parcel source) { super(source); // Get the current preference‘s value value = source.readInt(); // Change this to read the appropriate data type } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); // Write the preference‘s value dest.writeInt(value); // Change this to write the appropriate data type } // Standard creator object using an instance of this class public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; }
With the above implementation of Preference.BaseSavedState
added to your app (usually as a subclass of your Preference
subclass), you then need to implement the onSaveInstanceState()
andonRestoreInstanceState()
methods for your Preference
subclass.
For example:
@Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); // Check whether this Preference is persistent (continually saved) if (isPersistent()) { // No need to save instance state since it‘s persistent, // use superclass state return superState; } // Create instance of custom BaseSavedState final SavedState myState = new SavedState(superState); // Set the state‘s value with the class member that holds current // setting value myState.value = mNewValue; return myState; } @Override protected void onRestoreInstanceState(Parcelable state) { // Check whether we saved the state in onSaveInstanceState if (state == null || !state.getClass().equals(SavedState.class)) { // Didn‘t save the state, so call superclass super.onRestoreInstanceState(state); return; } // Cast state to custom BaseSavedState and pass to superclass SavedState myState = (SavedState) state; super.onRestoreInstanceState(myState.getSuperState()); // Set this Preference‘s widget to reflect the restored state mNumberPicker.setValue(myState.value); }
Android偏好设置(7)自定义Preference,和PreferenceDialog
标签:
原文地址:http://www.cnblogs.com/cocl/p/4621447.html