1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
|
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>
<p class="caution"><strong>Caution:</strong> When you call {@link
android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
registerOnSharedPreferenceChangeListener()}, the preference manager does not
currently store a strong reference to the listener. You must store a strong
reference to the listener, or it will be susceptible to garbage collection. We
recommend you keep a reference to the listener in the instance data of an object
that will exist as long as you need the listener.</p>
<p>For example, in the following code, the caller does not keep a reference to
the listener. As a result, the listener will be subject to garbage collection,
and it will fail at some indeterminate time in the future:</p>
<pre>
prefs.registerOnSharedPreferenceChangeListener(
// Bad! The listener is subject to garbage collection!
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// listener implementation
}
});
</pre>
<p>Instead, store a reference to the listener in an instance data field of an
object that will exist as long as the listener is needed:</p>
<pre>
SharedPreferences.OnSharedPreferenceChangeListener listener =
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// listener implementation
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
</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>
|