1174 lines
51 KiB
Plaintext
1174 lines
51 KiB
Plaintext
page.title=Settings
|
||
page.tags="preference","preferenceactivity","preferencefragment"
|
||
|
||
@jd:body
|
||
|
||
|
||
<div id="qv-wrapper">
|
||
<div id="qv">
|
||
|
||
<h2>In this document</h2>
|
||
<ol>
|
||
<li><a href="#Overview">Overview</a>
|
||
<ol>
|
||
<li><a href="#SettingTypes">Preferences</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="#DefiningPrefs">Defining Preferences in XML</a>
|
||
<ol>
|
||
<li><a href="#Groups">Creating setting groups</a></li>
|
||
<li><a href="#Intents">Using intents</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="#Activity">Creating a Preference Activity</a></li>
|
||
<li><a href="#Fragment">Using Preference Fragments</a></li>
|
||
<li><a href="#Defaults">Setting Default Values</a></li>
|
||
<li><a href="#PreferenceHeaders">Using Preference Headers</a>
|
||
<ol>
|
||
<li><a href="#CreateHeaders">Creating the headers file</a></li>
|
||
<li><a href="#DisplayHeaders">Displaying the headers</a></li>
|
||
<li><a href="#BackCompatHeaders">Supporting older versions with preference headers</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="#ReadingPrefs">Reading Preferences</a>
|
||
<ol>
|
||
<li><a href="#Listening">Listening for preference changes</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="#NetworkUsage">Managing Network Usage</a></li>
|
||
<li><a href="#Custom">Building a Custom Preference</a>
|
||
<ol>
|
||
<li><a href="#CustomSelected">Specifying the user interface</a></li>
|
||
<li><a href="#CustomSave">Saving the setting's value</a></li>
|
||
<li><a href="#CustomInitialize">Initializing the current value</a></li>
|
||
<li><a href="#CustomDefault">Providing a default value</a></li>
|
||
<li><a href="#CustomSaveState">Saving and restoring the Preference's state</a></li>
|
||
</ol>
|
||
</li>
|
||
</ol>
|
||
|
||
<h2>Key classes</h2>
|
||
<ol>
|
||
<li>{@link android.preference.Preference}</li>
|
||
<li>{@link android.preference.PreferenceActivity}</li>
|
||
<li>{@link android.preference.PreferenceFragment}</li>
|
||
</ol>
|
||
|
||
|
||
<h2>See also</h2>
|
||
<ol>
|
||
<li><a
|
||
href="{@docRoot}design/patterns/settings.html">Settings design guide</a></li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<p>Applications often include settings that allow users to modify app features and behaviors. For
|
||
example, some apps allow users to specify whether notifications are enabled or specify how often the
|
||
application syncs data with the cloud.</p>
|
||
|
||
<p>If you want to provide settings for your app, you should use
|
||
Android's {@link android.preference.Preference} APIs to build an interface that's consistent with
|
||
the user experience in other Android apps (including the system settings). This document describes
|
||
how to build your app settings using {@link android.preference.Preference} APIs.</p>
|
||
|
||
<div class="note design">
|
||
<p><strong>Settings Design</strong></p>
|
||
<p>For information about how to design your settings, read the <a
|
||
href="{@docRoot}design/patterns/settings.html">Settings</a> design guide.</p>
|
||
</div>
|
||
|
||
|
||
<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" />
|
||
<p class="img-caption"><strong>Figure 1.</strong> Screenshots from the Android Messaging app's
|
||
settings. Selecting an item defined by a {@link android.preference.Preference}
|
||
opens an interface to change the setting.</p>
|
||
|
||
|
||
|
||
|
||
<h2 id="Overview">Overview</h2>
|
||
|
||
<p>Instead of using {@link android.view.View} objects to build the user interface, settings are
|
||
built using various subclasses of the {@link android.preference.Preference} class that you
|
||
declare in an XML file.</p>
|
||
|
||
<p>A {@link android.preference.Preference} object is the building block for a single
|
||
setting. Each {@link android.preference.Preference} appears as an item in a list and provides the
|
||
appropriate UI for users to modify the setting. For example, a {@link
|
||
android.preference.CheckBoxPreference} creates a list item that shows a checkbox, and a {@link
|
||
android.preference.ListPreference} creates an item that opens a dialog with a list of choices.</p>
|
||
|
||
<p>Each {@link android.preference.Preference} you add has a corresponding key-value pair that
|
||
the system uses to save the setting in a default {@link android.content.SharedPreferences}
|
||
file for your app's settings. When the user changes a setting, the system updates the corresponding
|
||
value in the {@link android.content.SharedPreferences} file for you. The only time you should
|
||
directly interact with the associated {@link android.content.SharedPreferences} file is when you
|
||
need to read the value in order to determine your app's behavior based on the user's setting.</p>
|
||
|
||
<p>The value saved in {@link android.content.SharedPreferences} for each setting can be one of the
|
||
following data types:</p>
|
||
|
||
<ul>
|
||
<li>Boolean</li>
|
||
<li>Float</li>
|
||
<li>Int</li>
|
||
<li>Long</li>
|
||
<li>String</li>
|
||
<li>String {@link java.util.Set}</li>
|
||
</ul>
|
||
|
||
<p>Because your app's settings UI is built using {@link android.preference.Preference} objects
|
||
instead of
|
||
{@link android.view.View} objects, you need to use a specialized {@link android.app.Activity} or
|
||
{@link android.app.Fragment} subclass to display the list settings:</p>
|
||
|
||
<ul>
|
||
<li>If your app supports versions of Android older than 3.0 (API level 10 and lower), you must
|
||
build the activity as an extension of the {@link android.preference.PreferenceActivity} class.</li>
|
||
<li>On Android 3.0 and later, you should instead use a traditional {@link android.app.Activity}
|
||
that hosts a {@link android.preference.PreferenceFragment} that displays your app settings.
|
||
However, you can also use {@link android.preference.PreferenceActivity} to create a two-pane layout
|
||
for large screens when you have multiple groups of settings.</li>
|
||
</ul>
|
||
|
||
<p>How to set up your {@link android.preference.PreferenceActivity} and instances of {@link
|
||
android.preference.PreferenceFragment} is discussed in the sections about <a
|
||
href="#Activity">Creating a Preference Activity</a> and <a href="#Fragment">Using
|
||
Preference Fragments</a>.</p>
|
||
|
||
|
||
<h3 id="SettingTypes">Preferences</h3>
|
||
|
||
<p>Every setting for your app is represented by a specific subclass of the {@link
|
||
android.preference.Preference} class. Each subclass includes a set of core properties that allow you
|
||
to specify things such as a title for the setting and the default value. Each subclass also provides
|
||
its own specialized properties and user interface. For instance, figure 1 shows a screenshot from
|
||
the Messaging app's settings. Each list item in the settings screen is backed by a different {@link
|
||
android.preference.Preference} object.</p>
|
||
|
||
<p>A few of the most common preferences are:</p>
|
||
|
||
<dl>
|
||
<dt>{@link android.preference.CheckBoxPreference}</dt>
|
||
<dd>Shows an item with a checkbox for a setting that is either enabled or disabled. The saved
|
||
value is a boolean (<code>true</code> if it's checked).</dd>
|
||
|
||
<dt>{@link android.preference.ListPreference}</dt>
|
||
<dd>Opens a dialog with a list of radio buttons. The saved value
|
||
can be any one of the supported value types (listed above).</dd>
|
||
|
||
<dt>{@link android.preference.EditTextPreference}</dt>
|
||
<dd>Opens a dialog with an {@link android.widget.EditText} widget. The saved value is a {@link
|
||
java.lang.String}.</dd>
|
||
</dl>
|
||
|
||
<p>See the {@link android.preference.Preference} class for a list of all other subclasses and their
|
||
corresponding properties.</p>
|
||
|
||
<p>Of course, the built-in classes don't accommodate every need and your application might require
|
||
something more specialized. For example, the platform currently does not provide a {@link
|
||
android.preference.Preference} class for picking a number or a date. So you might need to define
|
||
your own {@link android.preference.Preference} subclass. For help doing so, see the section about <a
|
||
href="#Custom">Building a Custom Preference</a>.</p>
|
||
|
||
|
||
|
||
<h2 id="DefiningPrefs">Defining Preferences in XML</h2>
|
||
|
||
<p>Although you can instantiate new {@link android.preference.Preference} objects at runtime, you
|
||
should define your list of settings in XML with a hierarchy of {@link android.preference.Preference}
|
||
objects. Using an XML file to define your collection of settings is preferred because the file
|
||
provides an easy-to-read structure that's simple to update. Also, your app's settings are
|
||
generally pre-determined, although you can still modify the collection at runtime.</p>
|
||
|
||
<p>Each {@link android.preference.Preference} subclass can be declared with an XML element that
|
||
matches the class name, such as {@code <CheckBoxPreference>}.</p>
|
||
|
||
<p>You must save the XML file in the {@code res/xml/} directory. Although you can name the file
|
||
anything you want, it's traditionally named {@code preferences.xml}. You usually need only one file,
|
||
because branches in the hierarchy (that open their own list of settings) are declared using nested
|
||
instances of {@link android.preference.PreferenceScreen}.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> If you want to create a multi-pane layout for your
|
||
settings, then you need separate XML files for each fragment.</p>
|
||
|
||
<p>The root node for the XML file must be a {@link android.preference.PreferenceScreen
|
||
<PreferenceScreen>} element. Within this element is where you add each {@link
|
||
android.preference.Preference}. Each child you add within the
|
||
{@link android.preference.PreferenceScreen <PreferenceScreen>} element appears as a single
|
||
item in the list of settings.</p>
|
||
|
||
<p>For example:</p>
|
||
|
||
<pre>
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<CheckBoxPreference
|
||
android:key="pref_sync"
|
||
android:title="@string/pref_sync"
|
||
android:summary="@string/pref_sync_summ"
|
||
android:defaultValue="true" />
|
||
<ListPreference
|
||
android:dependency="pref_sync"
|
||
android:key="pref_syncConnectionType"
|
||
android:title="@string/pref_syncConnectionType"
|
||
android:dialogTitle="@string/pref_syncConnectionType"
|
||
android:entries="@array/pref_syncConnectionTypes_entries"
|
||
android:entryValues="@array/pref_syncConnectionTypes_values"
|
||
android:defaultValue="@string/pref_syncConnectionTypes_default" />
|
||
</PreferenceScreen>
|
||
</pre>
|
||
|
||
<p>In this example, there's a {@link android.preference.CheckBoxPreference} and a {@link
|
||
android.preference.ListPreference}. Both items include the following three attributes:</p>
|
||
|
||
<dl>
|
||
<dt>{@code android:key}</dt>
|
||
<dd>This attribute is required for preferences that persist a data value. It specifies the unique
|
||
key (a string) the system uses when saving this setting's value in the {@link
|
||
android.content.SharedPreferences}.
|
||
<p>The only instances in which this attribute is <em>not required</em> is when the preference is a
|
||
{@link android.preference.PreferenceCategory} or {@link android.preference.PreferenceScreen}, or the
|
||
preference specifies an {@link android.content.Intent} to invoke (with an <a
|
||
href="#Intents">{@code <intent>}</a> element) or a {@link android.app.Fragment} to display (with an <a
|
||
href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
|
||
android:fragment}</a> attribute).</p>
|
||
</dd>
|
||
<dt>{@code android:title}</dt>
|
||
<dd>This provides a user-visible name for the setting.</dd>
|
||
<dt>{@code android:defaultValue}</dt>
|
||
<dd>This specifies the initial value that the system should set in the {@link
|
||
android.content.SharedPreferences} file. You should supply a default value for all
|
||
settings.</dd>
|
||
</dl>
|
||
|
||
<p>For information about all other supported attributes, see the {@link
|
||
android.preference.Preference} (and respective subclass) documentation.</p>
|
||
|
||
|
||
<div class="figure" style="width:300px">
|
||
<img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" />
|
||
<p class="img-caption"><strong>Figure 2.</strong> Setting categories
|
||
with titles. <br/><b>1.</b> The category is specified by the {@link
|
||
android.preference.PreferenceCategory <PreferenceCategory>} element. <br/><b>2.</b> The title is
|
||
specified with the {@code android:title} attribute.</p>
|
||
</div>
|
||
|
||
|
||
<p>When your list of settings exceeds about 10 items, you might want to add titles to
|
||
define groups of settings or display those groups in a
|
||
separate screen. These options are described in the following sections.</p>
|
||
|
||
|
||
<h3 id="Groups">Creating setting groups</h3>
|
||
|
||
<p>If you present a list of 10 or more settings, users
|
||
may have difficulty scanning, comprehending, and processing them. You can remedy this by
|
||
dividing some or all of the settings into groups, effectively turning one long list into multiple
|
||
shorter lists. A group of related settings can be presented in one of two ways:</p>
|
||
|
||
<ul>
|
||
<li><a href="#Titles">Using titles</a></li>
|
||
<li><a href="#Subscreens">Using subscreens</a></li>
|
||
</ul>
|
||
|
||
<p>You can use one or both of these grouping techniques to organize your app's settings. When
|
||
deciding which to use and how to divide your settings, you should follow the guidelines in Android
|
||
Design's <a href="{@docRoot}design/patterns/settings.html">Settings</a> guide.</p>
|
||
|
||
|
||
<h4 id="Titles">Using titles</h4>
|
||
|
||
<p>If you want to provide dividers with headings between groups of settings (as shown in figure 2),
|
||
place each group of {@link android.preference.Preference} objects inside a {@link
|
||
android.preference.PreferenceCategory}.</p>
|
||
|
||
<p>For example:</p>
|
||
|
||
<pre>
|
||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<PreferenceCategory
|
||
android:title="@string/pref_sms_storage_title"
|
||
android:key="pref_key_storage_settings">
|
||
<CheckBoxPreference
|
||
android:key="pref_key_auto_delete"
|
||
android:summary="@string/pref_summary_auto_delete"
|
||
android:title="@string/pref_title_auto_delete"
|
||
android:defaultValue="false"... />
|
||
<Preference
|
||
android:key="pref_key_sms_delete_limit"
|
||
android:dependency="pref_key_auto_delete"
|
||
android:summary="@string/pref_summary_delete_limit"
|
||
android:title="@string/pref_title_sms_delete"... />
|
||
<Preference
|
||
android:key="pref_key_mms_delete_limit"
|
||
android:dependency="pref_key_auto_delete"
|
||
android:summary="@string/pref_summary_delete_limit"
|
||
android:title="@string/pref_title_mms_delete" ... />
|
||
</PreferenceCategory>
|
||
...
|
||
</PreferenceScreen>
|
||
</pre>
|
||
|
||
|
||
<h4 id="Subscreens">Using subscreens</h4>
|
||
|
||
<p>If you want to place groups of settings into a subscreen (as shown in figure 3), place the group
|
||
of {@link android.preference.Preference} objects inside a {@link
|
||
android.preference.PreferenceScreen}.</p>
|
||
|
||
<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" />
|
||
<p class="img-caption"><strong>Figure 3.</strong> Setting subscreens. The {@code
|
||
<PreferenceScreen>} element
|
||
creates an item that, when selected, opens a separate list to display the nested settings.</p>
|
||
|
||
<p>For example:</p>
|
||
|
||
<pre>
|
||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<!-- opens a subscreen of settings -->
|
||
<PreferenceScreen
|
||
android:key="button_voicemail_category_key"
|
||
android:title="@string/voicemail"
|
||
android:persistent="false">
|
||
<ListPreference
|
||
android:key="button_voicemail_provider_key"
|
||
android:title="@string/voicemail_provider" ... />
|
||
<!-- opens another nested subscreen -->
|
||
<PreferenceScreen
|
||
android:key="button_voicemail_setting_key"
|
||
android:title="@string/voicemail_settings"
|
||
android:persistent="false">
|
||
...
|
||
</PreferenceScreen>
|
||
<RingtonePreference
|
||
android:key="button_voicemail_ringtone_key"
|
||
android:title="@string/voicemail_ringtone_title"
|
||
android:ringtoneType="notification" ... />
|
||
...
|
||
</PreferenceScreen>
|
||
...
|
||
</PreferenceScreen>
|
||
</pre>
|
||
|
||
|
||
<h3 id="Intents">Using intents</h3>
|
||
|
||
<p>In some cases, you might want a preference item to open a different activity instead of a
|
||
settings screen, such as a web browser to view a web page. To invoke an {@link
|
||
android.content.Intent} when the user selects a preference item, add an {@code <intent>}
|
||
element as a child of the corresponding {@code <Preference>} element.</p>
|
||
|
||
<p>For example, here's how you can use a preference item to open a web page:</p>
|
||
|
||
<pre>
|
||
<Preference android:title="@string/prefs_web_page" >
|
||
<intent android:action="android.intent.action.VIEW"
|
||
android:data="http://www.example.com" />
|
||
</Preference>
|
||
</pre>
|
||
|
||
<p>You can create both implicit and explicit intents using the following attributes:</p>
|
||
|
||
<dl>
|
||
<dt>{@code android:action}</dt>
|
||
<dd>The action to assign, as per the {@link android.content.Intent#setAction setAction()}
|
||
method.</dd>
|
||
<dt>{@code android:data}</dt>
|
||
<dd>The data to assign, as per the {@link android.content.Intent#setData setData()} method.</dd>
|
||
<dt>{@code android:mimeType}</dt>
|
||
<dd>The MIME type to assign, as per the {@link android.content.Intent#setType setType()}
|
||
method.</dd>
|
||
<dt>{@code android:targetClass}</dt>
|
||
<dd>The class part of the component name, as per the {@link android.content.Intent#setComponent
|
||
setComponent()} method.</dd>
|
||
<dt>{@code android:targetPackage}</dt>
|
||
<dd>The package part of the component name, as per the {@link
|
||
android.content.Intent#setComponent setComponent()} method.</dd>
|
||
</dl>
|
||
|
||
|
||
|
||
<h2 id="Activity">Creating a Preference Activity</h2>
|
||
|
||
<p>To display your settings in an activity, extend the {@link
|
||
android.preference.PreferenceActivity} class. This is an extension of the traditional {@link
|
||
android.app.Activity} class that displays a list of settings based on a hierarchy of {@link
|
||
android.preference.Preference} objects. The {@link android.preference.PreferenceActivity}
|
||
automatically persists the settings associated with each {@link
|
||
android.preference.Preference} when the user makes a change.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> If you're developing your application for Android 3.0 and
|
||
higher, you should instead use {@link android.preference.PreferenceFragment}. Go to the next
|
||
section about <a href="#Fragment">Using Preference Fragments</a>.</p>
|
||
|
||
<p>The most important thing to remember is that you do not load a layout of views during the {@link
|
||
android.preference.PreferenceActivity#onCreate onCreate()} callback. Instead, you call {@link
|
||
android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} to
|
||
add the preferences you've declared in an XML file to the activity. For example, here's the bare
|
||
minimum code required for a functional {@link android.preference.PreferenceActivity}:</p>
|
||
|
||
<pre>
|
||
public class SettingsActivity extends PreferenceActivity {
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
addPreferencesFromResource(R.xml.preferences);
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>This is actually enough code for some apps, because as soon as the user modifies a preference,
|
||
the system saves the changes to a default {@link android.content.SharedPreferences} file that your
|
||
other application components can read when you need to check the user's settings. Many apps,
|
||
however, require a little more code in order to listen for changes that occur to the preferences.
|
||
For information about listening to changes in the {@link android.content.SharedPreferences} file,
|
||
see the section about <a href="#ReadingPrefs">Reading Preferences</a>.</p>
|
||
|
||
|
||
|
||
|
||
<h2 id="Fragment">Using Preference Fragments</h2>
|
||
|
||
<p>If you're developing for Android 3.0 (API level 11) and higher, you should use a {@link
|
||
android.preference.PreferenceFragment} to display your list of {@link android.preference.Preference}
|
||
objects. You can add a {@link android.preference.PreferenceFragment} to any activity—you don't
|
||
need to use {@link android.preference.PreferenceActivity}.</p>
|
||
|
||
<p><a href="{@docRoot}guide/components/fragments.html">Fragments</a> provide a more
|
||
flexible architecture for your application, compared to using activities alone, no matter what kind
|
||
of activity you're building. As such, we suggest you use {@link
|
||
android.preference.PreferenceFragment} to control the display of your settings instead of {@link
|
||
android.preference.PreferenceActivity} when possible.</p>
|
||
|
||
<p>Your implementation of {@link android.preference.PreferenceFragment} can be as simple as
|
||
defining the {@link android.preference.PreferenceFragment#onCreate onCreate()} method to load a
|
||
preferences file with {@link android.preference.PreferenceFragment#addPreferencesFromResource
|
||
addPreferencesFromResource()}. For example:</p>
|
||
|
||
<pre>
|
||
public static class SettingsFragment extends PreferenceFragment {
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
|
||
// Load the preferences from an XML resource
|
||
addPreferencesFromResource(R.xml.preferences);
|
||
}
|
||
...
|
||
}
|
||
</pre>
|
||
|
||
<p>You can then add this fragment to an {@link android.app.Activity} just as you would for any other
|
||
{@link android.app.Fragment}. For example:</p>
|
||
|
||
<pre>
|
||
public class SettingsActivity extends Activity {
|
||
@Override
|
||
protected void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
|
||
// Display the fragment as the main content.
|
||
getFragmentManager().beginTransaction()
|
||
.replace(android.R.id.content, new SettingsFragment())
|
||
.commit();
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p class="note"><strong>Note:</strong> A {@link android.preference.PreferenceFragment} doesn't have
|
||
a its own {@link android.content.Context} object. If you need a {@link android.content.Context}
|
||
object, you can call {@link android.app.Fragment#getActivity()}. However, be careful to call
|
||
{@link android.app.Fragment#getActivity()} only when the fragment is attached to an activity. When
|
||
the fragment is not yet attached, or was detached during the end of its lifecycle, {@link
|
||
android.app.Fragment#getActivity()} will return null.</p>
|
||
|
||
|
||
<h2 id="Defaults">Setting Default Values</h2>
|
||
|
||
<p>The preferences you create probably define some important behaviors for your application, so it's
|
||
necessary that you initialize the associated {@link android.content.SharedPreferences} file with
|
||
default values for each {@link android.preference.Preference} when the user first opens your
|
||
application.</p>
|
||
|
||
<p>The first thing you must do is specify a default value for each {@link
|
||
android.preference.Preference}
|
||
object in your XML file using the {@code android:defaultValue} attribute. The value can be any data
|
||
type that is appropriate for the corresponding {@link android.preference.Preference} object. For
|
||
example:</p>
|
||
|
||
<pre>
|
||
<!-- default value is a boolean -->
|
||
<CheckBoxPreference
|
||
android:defaultValue="true"
|
||
... />
|
||
|
||
<!-- default value is a string -->
|
||
<ListPreference
|
||
android:defaultValue="@string/pref_syncConnectionTypes_default"
|
||
... />
|
||
</pre>
|
||
|
||
<p>Then, from the {@link android.app.Activity#onCreate onCreate()} method in your application's main
|
||
activity—and in any other activity through which the user may enter your application for the
|
||
first time—call {@link android.preference.PreferenceManager#setDefaultValues
|
||
setDefaultValues()}:</p>
|
||
|
||
<pre>
|
||
PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
|
||
</pre>
|
||
|
||
<p>Calling this during {@link android.app.Activity#onCreate onCreate()} ensures that your
|
||
application is properly initialized with default settings, which your application might need to
|
||
read in order to determine some behaviors (such as whether to download data while on a
|
||
cellular network).</p>
|
||
|
||
<p>This method takes three arguments:</p>
|
||
<ul>
|
||
<li>Your application {@link android.content.Context}.</li>
|
||
<li>The resource ID for the preference XML file for which you want to set the default values.</li>
|
||
<li>A boolean indicating whether the default values should be set more than once.
|
||
<p>When <code>false</code>, the system sets the default values only if this method has never been
|
||
called in the past (or the {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
|
||
in the default value shared preferences file is false).</p></li>
|
||
</ul>
|
||
|
||
<p>As long as you set the third argument to <code>false</code>, you can safely call this method
|
||
every time your activity starts without overriding the user's saved preferences by resetting them to
|
||
the defaults. However, if you set it to <code>true</code>, you will override any previous
|
||
values with the defaults.</p>
|
||
|
||
|
||
|
||
<h2 id="PreferenceHeaders">Using Preference Headers</h2>
|
||
|
||
<p>In rare cases, you might want to design your settings such that the first screen
|
||
displays only a list of <a href="#Subscreens">subscreens</a> (such as in the system Settings app,
|
||
as shown in figures 4 and 5). When you're developing such a design for Android 3.0 and higher, you
|
||
should use a new "headers" feature in Android 3.0, instead of building subscreens with nested
|
||
{@link android.preference.PreferenceScreen} elements.</p>
|
||
|
||
<p>To build your settings with headers, you need to:</p>
|
||
<ol>
|
||
<li>Separate each group of settings into separate instances of {@link
|
||
android.preference.PreferenceFragment}. That is, each group of settings needs a separate XML
|
||
file.</li>
|
||
<li>Create an XML headers file that lists each settings group and declares which fragment
|
||
contains the corresponding list of settings.</li>
|
||
<li>Extend the {@link android.preference.PreferenceActivity} class to host your settings.</li>
|
||
<li>Implement the {@link
|
||
android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} callback to specify the
|
||
headers file.</li>
|
||
</ol>
|
||
|
||
<p>A great benefit to using this design is that {@link android.preference.PreferenceActivity}
|
||
automatically presents the two-pane layout shown in figure 4 when running on large screens.</p>
|
||
|
||
<p>Even if your application supports versions of Android older than 3.0, you can build your
|
||
application to use {@link android.preference.PreferenceFragment} for a two-pane presentation on
|
||
newer devices while still supporting a traditional multi-screen hierarchy on older
|
||
devices (see the section about <a href="#BackCompatHeaders">Supporting older versions with
|
||
preference headers</a>).</p>
|
||
|
||
<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
|
||
<p class="img-caption"><strong>Figure 4.</strong> Two-pane layout with headers. <br/><b>1.</b> The
|
||
headers are defined with an XML headers file. <br/><b>2.</b> Each group of settings is defined by a
|
||
{@link android.preference.PreferenceFragment} that's specified by a {@code <header>} element in
|
||
the headers file.</p>
|
||
|
||
<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" />
|
||
<p class="img-caption"><strong>Figure 5.</strong> A handset device with setting headers. When an
|
||
item is selected, the associated {@link android.preference.PreferenceFragment} replaces the
|
||
headers.</p>
|
||
|
||
|
||
<h3 id="CreateHeaders" style="clear:left">Creating the headers file</h3>
|
||
|
||
<p>Each group of settings in your list of headers is specified by a single {@code <header>}
|
||
element inside a root {@code <preference-headers>} element. For example:</p>
|
||
|
||
<pre>
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<header
|
||
android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
|
||
android:title="@string/prefs_category_one"
|
||
android:summary="@string/prefs_summ_category_one" />
|
||
<header
|
||
android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
|
||
android:title="@string/prefs_category_two"
|
||
android:summary="@string/prefs_summ_category_two" >
|
||
<!-- key/value pairs can be included as arguments for the fragment. -->
|
||
<extra android:name="someKey" android:value="someHeaderValue" />
|
||
</header>
|
||
</preference-headers>
|
||
</pre>
|
||
|
||
<p>With the {@code android:fragment} attribute, each header declares an instance of {@link
|
||
android.preference.PreferenceFragment} that should open when the user selects the header.</p>
|
||
|
||
<p>The {@code <extras>} element allows you to pass key-value pairs to the fragment in a {@link
|
||
android.os.Bundle}. The fragment can retrieve the arguments by calling {@link
|
||
android.app.Fragment#getArguments()}. You might pass arguments to the fragment for a variety of
|
||
reasons, but one good reason is to reuse the same subclass of {@link
|
||
android.preference.PreferenceFragment} for each group and use the argument to specify which
|
||
preferences XML file the fragment should load.</p>
|
||
|
||
<p>For example, here's a fragment that can be reused for multiple settings groups, when each
|
||
header defines an {@code <extra>} argument with the {@code "settings"} key:</p>
|
||
|
||
<pre>
|
||
public static class SettingsFragment extends PreferenceFragment {
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
|
||
String settings = getArguments().getString("settings");
|
||
if ("notifications".equals(settings)) {
|
||
addPreferencesFromResource(R.xml.settings_wifi);
|
||
} else if ("sync".equals(settings)) {
|
||
addPreferencesFromResource(R.xml.settings_sync);
|
||
}
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
|
||
|
||
<h3 id="DisplayHeaders">Displaying the headers</h3>
|
||
|
||
<p>To display the preference headers, you must implement the {@link
|
||
android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} callback method and call
|
||
{@link android.preference.PreferenceActivity#loadHeadersFromResource
|
||
loadHeadersFromResource()}. For example:</p>
|
||
|
||
<pre>
|
||
public class SettingsActivity extends PreferenceActivity {
|
||
@Override
|
||
public void onBuildHeaders(List<Header> target) {
|
||
loadHeadersFromResource(R.xml.preference_headers, target);
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>When the user selects an item from the list of headers, the system opens the associated {@link
|
||
android.preference.PreferenceFragment}.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> When using preference headers, your subclass of {@link
|
||
android.preference.PreferenceActivity} doesn't need to implement the {@link
|
||
android.preference.PreferenceActivity#onCreate onCreate()} method, because the only required
|
||
task for the activity is to load the headers.</p>
|
||
|
||
|
||
<h3 id="BackCompatHeaders">Supporting older versions with preference headers</h3>
|
||
|
||
<p>If your application supports versions of Android older than 3.0, you can still use headers to
|
||
provide a two-pane layout when running on Android 3.0 and higher. All you need to do is create an
|
||
additional preferences XML file that uses basic {@link android.preference.Preference
|
||
<Preference>} elements that behave like the header items (to be used by the older Android
|
||
versions).</p>
|
||
|
||
<p>Instead of opening a new {@link android.preference.PreferenceScreen}, however, each of the {@link
|
||
android.preference.Preference <Preference>} elements sends an {@link android.content.Intent} to
|
||
the {@link android.preference.PreferenceActivity} that specifies which preference XML file to
|
||
load.</p>
|
||
|
||
<p>For example, here's an XML file for preference headers that is used on Android 3.0
|
||
and higher ({@code res/xml/preference_headers.xml}):</p>
|
||
|
||
<pre>
|
||
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<header
|
||
android:fragment="com.example.prefs.SettingsFragmentOne"
|
||
android:title="@string/prefs_category_one"
|
||
android:summary="@string/prefs_summ_category_one" />
|
||
<header
|
||
android:fragment="com.example.prefs.SettingsFragmentTwo"
|
||
android:title="@string/prefs_category_two"
|
||
android:summary="@string/prefs_summ_category_two" />
|
||
</preference-headers>
|
||
</pre>
|
||
|
||
<p>And here is a preference file that provides the same headers for versions older than
|
||
Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p>
|
||
|
||
<pre>
|
||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<Preference
|
||
android:title="@string/prefs_category_one"
|
||
android:summary="@string/prefs_summ_category_one" >
|
||
<intent
|
||
android:targetPackage="com.example.prefs"
|
||
android:targetClass="com.example.prefs.SettingsActivity"
|
||
android:action="com.example.prefs.PREFS_ONE" />
|
||
</Preference>
|
||
<Preference
|
||
android:title="@string/prefs_category_two"
|
||
android:summary="@string/prefs_summ_category_two" >
|
||
<intent
|
||
android:targetPackage="com.example.prefs"
|
||
android:targetClass="com.example.prefs.SettingsActivity"
|
||
android:action="com.example.prefs.PREFS_TWO" />
|
||
</Preference>
|
||
</PreferenceScreen>
|
||
</pre>
|
||
|
||
<p>Because support for {@code <preference-headers>} was added in Android 3.0, the system calls
|
||
{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} in your {@link
|
||
android.preference.PreferenceActivity} only when running on Androd 3.0 or higher. In order to load
|
||
the "legacy" headers file ({@code preference_headers_legacy.xml}), you must check the Android
|
||
version and, if the version is older than Android 3.0 ({@link
|
||
android.os.Build.VERSION_CODES#HONEYCOMB}), call {@link
|
||
android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} to
|
||
load the legacy header file. For example:</p>
|
||
|
||
<pre>
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
...
|
||
|
||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||
// Load the legacy preferences headers
|
||
addPreferencesFromResource(R.xml.preference_headers_legacy);
|
||
}
|
||
}
|
||
|
||
// Called only on Honeycomb and later
|
||
@Override
|
||
public void onBuildHeaders(List<Header> target) {
|
||
loadHeadersFromResource(R.xml.preference_headers, target);
|
||
}
|
||
</pre>
|
||
|
||
<p>The only thing left to do is handle the {@link android.content.Intent} that's passed into the
|
||
activity to identify which preference file to load. So retrieve the intent's action and compare it
|
||
to known action strings that you've used in the preference XML's {@code <intent>} tags:</p>
|
||
|
||
<pre>
|
||
final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
|
||
...
|
||
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
|
||
String action = getIntent().getAction();
|
||
if (action != null && action.equals(ACTION_PREFS_ONE)) {
|
||
addPreferencesFromResource(R.xml.preferences);
|
||
}
|
||
...
|
||
|
||
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||
// Load the legacy preferences headers
|
||
addPreferencesFromResource(R.xml.preference_headers_legacy);
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>Beware that consecutive calls to {@link
|
||
android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} will
|
||
stack all the preferences in a single list, so be sure that it's only called once by chaining the
|
||
conditions with else-if statements.</p>
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="ReadingPrefs">Reading Preferences</h2>
|
||
|
||
<p>By default, all your app's preferences are saved to a file that's accessible from anywhere
|
||
within your application by calling the static method {@link
|
||
android.preference.PreferenceManager#getDefaultSharedPreferences
|
||
PreferenceManager.getDefaultSharedPreferences()}. This returns the {@link
|
||
android.content.SharedPreferences} object containing all the key-value pairs that are associated
|
||
with the {@link android.preference.Preference} objects used in your {@link
|
||
android.preference.PreferenceActivity}.</p>
|
||
|
||
<p>For example, here's how you can read one of the preference values from any other activity in your
|
||
application:</p>
|
||
|
||
<pre>
|
||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||
String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
|
||
</pre>
|
||
|
||
|
||
|
||
<h3 id="Listening">Listening for preference changes</h3>
|
||
|
||
<p>There are several reasons you might want to be notified as soon as the use changes one of the
|
||
preferences. In order to receive a callback when a change happens to any one of the preferences,
|
||
implement the {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||
SharedPreference.OnSharedPreferenceChangeListener} interface and register the listener for the
|
||
{@link android.content.SharedPreferences} object by calling {@link
|
||
android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
|
||
registerOnSharedPreferenceChangeListener()}.</p>
|
||
|
||
<p>The interface has only one callback method, {@link
|
||
android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged
|
||
onSharedPreferenceChanged()}, and you might find it easiest to implement the interface as a part of
|
||
your activity. For example:</p>
|
||
|
||
<pre>
|
||
public class SettingsActivity extends PreferenceActivity
|
||
implements OnSharedPreferenceChangeListener {
|
||
public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
|
||
...
|
||
|
||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||
if (key.equals(KEY_PREF_SYNC_CONN)) {
|
||
Preference connectionPref = findPreference(key);
|
||
// Set summary to be the user-description for the selected value
|
||
connectionPref.setSummary(sharedPreferences.getString(key, ""));
|
||
}
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>In this example, the method checks whether the changed setting is for a known preference key. It
|
||
calls {@link android.preference.PreferenceActivity#findPreference findPreference()} to get the
|
||
{@link android.preference.Preference} object that was changed so it can modify the item's
|
||
summary to be a description of the user's selection. That is, when the setting is a {@link
|
||
android.preference.ListPreference} or other multiple choice setting, you should call {@link
|
||
android.preference.Preference#setSummary setSummary()} when the setting changes to display the
|
||
current status (such as the Sleep setting shown in figure 5).</p>
|
||
|
||
<p class="note"><strong>Note:</strong> As described in the Android Design document about <a
|
||
href="{@docRoot}design/patterns/settings.html">Settings</a>, we recommend that you update the
|
||
summary for a {@link android.preference.ListPreference} each time the user changes the preference in
|
||
order to describe the current setting.</p>
|
||
|
||
<p>For proper lifecycle management in the activity, we recommend that you register and unregister
|
||
your {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} during the {@link
|
||
android.app.Activity#onResume} and {@link android.app.Activity#onPause} callbacks, respectively:</p>
|
||
|
||
<pre>
|
||
@Override
|
||
protected void onResume() {
|
||
super.onResume();
|
||
getPreferenceScreen().getSharedPreferences()
|
||
.registerOnSharedPreferenceChangeListener(this);
|
||
}
|
||
|
||
@Override
|
||
protected void onPause() {
|
||
super.onPause();
|
||
getPreferenceScreen().getSharedPreferences()
|
||
.unregisterOnSharedPreferenceChangeListener(this);
|
||
}
|
||
</pre>
|
||
|
||
|
||
|
||
<h2 id="NetworkUsage">Managing Network Usage</h2>
|
||
|
||
|
||
<p>Beginning with Android 4.0, the system's Settings application allows users to see how much
|
||
network data their applications are using while in the foreground and background. Users can then
|
||
disable the use of background data for individual apps. In order to avoid users disabling your app's
|
||
access to data from the background, you should use the data connection efficiently and allow
|
||
users to refine your app's data usage through your application settings.<p>
|
||
|
||
<p>For example, you might allow the user to control how often your app syncs data, whether your app
|
||
performs uploads/downloads only when on Wi-Fi, whether your app uses data while roaming, etc. With
|
||
these controls available to them, users are much less likely to disable your app's access to data
|
||
when they approach the limits they set in the system Settings, because they can instead precisely
|
||
control how much data your app uses.</p>
|
||
|
||
<p>Once you've added the necessary preferences in your {@link android.preference.PreferenceActivity}
|
||
to control your app's data habits, you should add an intent filter for {@link
|
||
android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} in your manifest file. For example:</p>
|
||
|
||
<pre>
|
||
<activity android:name="SettingsActivity" ... >
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
|
||
<category android:name="android.intent.category.DEFAULT" />
|
||
</intent-filter>
|
||
</activity>
|
||
</pre>
|
||
|
||
<p>This intent filter indicates to the system that this is the activity that controls your
|
||
application's data usage. Thus, when the user inspects how much data your app is using from the
|
||
system's Settings app, a <em>View application settings</em> button is available that launches your
|
||
{@link android.preference.PreferenceActivity} so the user can refine how much data your app
|
||
uses.</p>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="Custom">Building a Custom Preference</h2>
|
||
|
||
<p>The Android framework includes a variety of {@link android.preference.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 {@link android.preference.Preference} class or one of the other subclasses.</p>
|
||
|
||
<p>When you extend the {@link android.preference.Preference} class, there are a few important
|
||
things you need to do:</p>
|
||
|
||
<ul>
|
||
<li>Specify the user interface that appears when the user selects the settings.</li>
|
||
<li>Save the setting's value when appropriate.</li>
|
||
<li>Initialize the {@link android.preference.Preference} with the current (or default) value
|
||
when it comes into view.</li>
|
||
<li>Provide the default value when requested by the system.</li>
|
||
<li>If the {@link android.preference.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).</li>
|
||
</ul>
|
||
|
||
<p>The following sections describe how to accomplish each of these tasks.</p>
|
||
|
||
|
||
|
||
<h3 id="CustomSelected">Specifying the user interface</h3>
|
||
|
||
<p>If you directly extend the {@link android.preference.Preference} class, you need to implement
|
||
{@link android.preference.Preference#onClick()} to define the action that occurs when the user
|
||
selects the item. However, most custom settings extend {@link android.preference.DialogPreference} to
|
||
show a dialog, which simplifies the procedure. When you extend {@link
|
||
android.preference.DialogPreference}, you must call {@link
|
||
android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} during in the
|
||
class constructor to specify the layout for the dialog.</p>
|
||
|
||
<p>For example, here's the constructor for a custom {@link
|
||
android.preference.DialogPreference} that declares the layout and specifies the text for the
|
||
default positive and negative dialog buttons:</p>
|
||
|
||
<pre>
|
||
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);
|
||
}
|
||
...
|
||
}
|
||
</pre>
|
||
|
||
|
||
|
||
<h3 id="CustomSave">Saving the setting's value</h3>
|
||
|
||
<p>You can save a value for the setting at any time by calling one of the {@link
|
||
android.preference.Preference} class's {@code persist*()} methods, such as {@link
|
||
android.preference.Preference#persistInt persistInt()} if the setting's value is an integer or
|
||
{@link android.preference.Preference#persistBoolean persistBoolean()} to save a boolean.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> Each {@link android.preference.Preference} can save only one
|
||
data type, so you must use the {@code persist*()} method appropriate for the data type used by your
|
||
custom {@link android.preference.Preference}.</p>
|
||
|
||
<p>When you choose to persist the setting can depend on which {@link
|
||
android.preference.Preference} class you extend. If you extend {@link
|
||
android.preference.DialogPreference}, then you should persist the value only when the dialog
|
||
closes due to a positive result (the user selects the "OK" button).</p>
|
||
|
||
<p>When a {@link android.preference.DialogPreference} closes, the system calls the {@link
|
||
android.preference.DialogPreference#onDialogClosed onDialogClosed()} method. The method includes a
|
||
boolean argument that specifies whether the user result is "positive"—if the value is
|
||
<code>true</code>, then the user selected the positive button and you should save the new value. For
|
||
example:</p>
|
||
|
||
<pre>
|
||
@Override
|
||
protected void onDialogClosed(boolean positiveResult) {
|
||
// When the user selects "OK", persist the new value
|
||
if (positiveResult) {
|
||
persistInt(mNewValue);
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>In this example, <code>mNewValue</code> is a class member that holds the setting's current
|
||
value. Calling {@link android.preference.Preference#persistInt persistInt()} saves the value to
|
||
the {@link android.content.SharedPreferences} file (automatically using the key that's
|
||
specified in the XML file for this {@link android.preference.Preference}).</p>
|
||
|
||
|
||
<h3 id="CustomInitialize">Initializing the current value</h3>
|
||
|
||
<p>When the system adds your {@link android.preference.Preference} to the screen, it
|
||
calls {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} to notify
|
||
you whether the setting has a persisted value. If there is no persisted value, this call provides
|
||
you the default value.</p>
|
||
|
||
<p>The {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} method passes
|
||
a boolean, <code>restorePersistedValue</code>, to indicate whether a value has already been persisted
|
||
for the setting. If it is <code>true</code>, then you should retrieve the persisted value by calling
|
||
one of the {@link
|
||
android.preference.Preference} class's {@code getPersisted*()} methods, such as {@link
|
||
android.preference.Preference#getPersistedInt 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.</p>
|
||
|
||
<p>If <code>restorePersistedValue</code> is <code>false</code>, then you
|
||
should use the default value that is passed in the second argument.</p>
|
||
|
||
<pre>
|
||
@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);
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>Each {@code 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 {@link
|
||
android.preference.Preference#getPersistedInt getPersistedInt()} can't return a persisted value.</p>
|
||
|
||
<p class="caution"><strong>Caution:</strong> You <strong>cannot</strong> use the
|
||
<code>defaultValue</code> as the default value in the {@code getPersisted*()} method, because
|
||
its value is always null when <code>restorePersistedValue</code> is <code>true</code>.</p>
|
||
|
||
|
||
<h3 id="CustomDefault">Providing a default value</h3>
|
||
|
||
<p>If the instance of your {@link android.preference.Preference} class specifies a default value
|
||
(with the {@code android:defaultValue} attribute), then the
|
||
system calls {@link android.preference.Preference#onGetDefaultValue
|
||
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 {@link
|
||
android.content.SharedPreferences}. For example:</p>
|
||
|
||
<pre>
|
||
@Override
|
||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||
return a.getInteger(index, DEFAULT_VALUE);
|
||
}
|
||
</pre>
|
||
|
||
<p>The method arguments provide everything you need: the array of attributes and the index
|
||
position of the {@code android: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.</p>
|
||
|
||
|
||
|
||
<h3 id="CustomSaveState">Saving and restoring the Preference's state</h3>
|
||
|
||
<p>Just like a {@link android.view.View} in a layout, your {@link android.preference.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 {@link android.preference.Preference} class, you must implement the
|
||
lifecycle callback methods {@link android.preference.Preference#onSaveInstanceState
|
||
onSaveInstanceState()} and {@link
|
||
android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p>
|
||
|
||
<p>The state of your {@link android.preference.Preference} is defined by an object that implements
|
||
the {@link android.os.Parcelable} interface. The Android framework provides such an object for you
|
||
as a starting point to define your state object: the {@link
|
||
android.preference.Preference.BaseSavedState} class.</p>
|
||
|
||
<p>To define how your {@link android.preference.Preference} class saves its state, you should
|
||
extend the {@link android.preference.Preference.BaseSavedState} class. You need to override just
|
||
a few methods and define the {@link android.preference.Preference.BaseSavedState#CREATOR}
|
||
object.</p>
|
||
|
||
<p>For most apps, you can copy the following implementation and simply change the lines that
|
||
handle the {@code value} if your {@link android.preference.Preference} subclass saves a data
|
||
type other than an integer.</p>
|
||
|
||
<pre>
|
||
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];
|
||
}
|
||
};
|
||
}
|
||
</pre>
|
||
|
||
<p>With the above implementation of {@link android.preference.Preference.BaseSavedState} added
|
||
to your app (usually as a subclass of your {@link android.preference.Preference} subclass), you
|
||
then need to implement the {@link android.preference.Preference#onSaveInstanceState
|
||
onSaveInstanceState()} and {@link
|
||
android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} methods for your
|
||
{@link android.preference.Preference} subclass.</p>
|
||
|
||
<p>For example:</p>
|
||
|
||
<pre>
|
||
@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);
|
||
}
|
||
</pre>
|
||
|