• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=설정
2page.tags=preference,preferenceactivity,preferencefragment
3
4@jd:body
5
6
7<div id="qv-wrapper">
8<div id="qv">
9
10<h2>이 문서의 내용</h2>
11<ol>
12  <li><a href="#Overview">개요</a>
13    <ol>
14      <li><a href="#SettingTypes">기본 설정</a></li>
15    </ol>
16  </li>
17  <li><a href="#DefiningPrefs">XML로 기본 설정 정의하기</a>
18    <ol>
19      <li><a href="#Groups">설정 그룹 만들기</a></li>
20      <li><a href="#Intents">인텐트 사용하기</a></li>
21    </ol>
22  </li>
23  <li><a href="#Activity">기본 설정 액티비티 만들기</a></li>
24  <li><a href="#Fragment">기본 설정 프래그먼트 사용하기</a></li>
25  <li><a href="#Defaults">설정 기본 값</a></li>
26  <li><a href="#PreferenceHeaders">기본 설정 헤더 사용하기</a>
27    <ol>
28      <li><a href="#CreateHeaders">헤더 파일 만들기</a></li>
29      <li><a href="#DisplayHeaders">헤더 표시하기</a></li>
30      <li><a href="#BackCompatHeaders">기본 설정 헤더로 이전 버전 지원하기</a></li>
31    </ol>
32  </li>
33  <li><a href="#ReadingPrefs">기본 설정 읽기</a>
34    <ol>
35      <li><a href="#Listening">기본 설정 변경 수신 대기</a></li>
36    </ol>
37  </li>
38  <li><a href="#NetworkUsage">네트워크 사용량 관리하기</a></li>
39  <li><a href="#Custom">사용자 지정 기본 설정 구축하기</a>
40    <ol>
41      <li><a href="#CustomSelected">사용자 인터페이스 지정하기</a></li>
42      <li><a href="#CustomSave">설정의 값 저장하기</a></li>
43      <li><a href="#CustomInitialize">현재 값 초기화하기</a></li>
44      <li><a href="#CustomDefault">기본 값 제공하기</a></li>
45      <li><a href="#CustomSaveState">기본 설정의 상태 저장 및 복원하기</a></li>
46    </ol>
47  </li>
48</ol>
49
50<h2>Key 클래스</h2>
51<ol>
52  <li>{@link android.preference.Preference}</li>
53  <li>{@link android.preference.PreferenceActivity}</li>
54  <li>{@link android.preference.PreferenceFragment}</li>
55</ol>
56
57
58<h2>참고 항목</h2>
59<ol>
60  <li><a href="{@docRoot}design/patterns/settings.html">설정 디자인 가이드</a></li>
61</ol>
62</div>
63</div>
64
65
66
67
68<p>애플리케이션에는 종종 설정이 포함되어 있어 사용자가 앱 기능과 행동을 수정할 수 있게 해줍니다. 예를 들어
69몇몇 앱은 사용자에게 알림을 활성화할지 여부를 지정하거나 애플리케이션이
70클라우드와 데이터를 동기화할 빈도를 지정할 수 있게 해줍니다.</p>
71
72<p>자신의 앱에 설정을 제공하고자 하는 경우, Android의
73{@link android.preference.Preference} API를 사용하여 다른 Android 앱(시스템 설정 포함)의 사용자 환경과
74일관성을 유지하는 인터페이스를 구축할 수 있게 해야 합니다. 이 문서에서는
75{@link android.preference.Preference} API를 사용하여 앱 설정을 구축하는 방법을 설명합니다.</p>
76
77<div class="note design">
78<p><strong>설정 디자인</strong></p>
79  <p>설정을 디자인하는 방법에 관련된 정보는 <a href="{@docRoot}design/patterns/settings.html">설정</a> 디자인 가이드를 읽어보십시오.</p>
80</div>
81
82
83<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" />
84<p class="img-caption"><strong>그림 1.</strong> Android 메시지 앱의 설정에서 가져온
85스크린샷입니다. {@link android.preference.Preference}가 정의한 항목을 선택하면
86인터페이스가 열려 설정을 변경할 수 있게 됩니다.</p>
87
88
89
90
91<h2 id="Overview">개요</h2>
92
93<p>사용자 인터페이스를 구축할 때에는 {@link android.view.View} 객체를 사용하지만, 설정은 그 대신
94{@link android.preference.Preference} 클래스의 다양한 하위 클래스를 사용하여 구축합니다.
95이와 같은 하위 클래스는 XML 파일에서 선언합니다.</p>
96
97<p>{@link android.preference.Preference} 객체는 하나의 설정을 이루는 기본
98단위입니다. 각각의 {@link android.preference.Preference}는 목록의 항목으로
99나타나며 사용자가 설정을 수정하기에 적절한 UI를 제공합니다. 예를 들어 {@link
100android.preference.CheckBoxPreference}는 확인란을 표시하는 목록 항목을 만들고, {@link
101android.preference.ListPreference}는 선택 목록이 있는 대화를 여는 항목을 만듭니다.</p>
102
103<p>각각의 {@link android.preference.Preference}를 추가할 때마다 상응하는 키-값 쌍이 있어
104시스템이 이를 사용하여 해당 설정을 앱의 설정에 대한 기본 {@link android.content.SharedPreferences}
105파일에 저장합니다. 사용자가 설정을 변경하면 시스템이
106{@link android.content.SharedPreferences} 파일에 있는 상응하는 값을 개발자 대신 업데이트합니다. 개발자가 직접
107연관된 {@link android.content.SharedPreferences} 파일과 상호 작용을 해야 하는 경우는
108사용자의 설정을 기반으로 앱의 동작을 결정하기 위해 값을 읽어야 할 때뿐입니다.</p>
109
110<p>각 설정에 대하여 {@link android.content.SharedPreferences}에 저장된 값은 다음과 같은
111데이터 유형 중 한 가지를 취할 수 있습니다.</p>
112
113<ul>
114  <li>Boolean</li>
115  <li>Float</li>
116  <li>Int</li>
117  <li>Long</li>
118  <li>String</li>
119  <li>String {@link java.util.Set}</li>
120</ul>
121
122<p>앱의 설정 UI는
123{@link android.view.View} 객체 대신
124{@link android.preference.Preference} 객체를 사용하여 구축되기 때문에, 목록 설정을 표시하려면 특수 {@link android.app.Activity} 또는
125{@link android.app.Fragment} 하위 클래스를 사용해야 합니다.</p>
126
127<ul>
128  <li>앱이 Android 3.0 이전 버전(API 레벨 10 이하)을 지원하는 경우, 액티비티를 구축할 때
129{@link android.preference.PreferenceActivity} 클래스의 확장으로 구축해야 합니다.</li>
130  <li>Android 3.0 이후의 경우에는 대신 기존의 {@link android.app.Activity}를
131사용해야 합니다. 이것은 앱 설정을 표시하는 {@link android.preference.PreferenceFragment}를 호스팅합니다.
132하지만, 여러 개의 설정 그룹이 있는 경우 {@link android.preference.PreferenceActivity}를 사용하여
133대형 화면에 맞는 창 두 개짜리 레이아웃을 만들 수도 있습니다.</li>
134</ul>
135
136<p>{@link android.preference.PreferenceActivity}와 {@link
137android.preference.PreferenceFragment}의 인스턴스를 설정하는 방법은 <a href="#Activity">기본 설정 액티비티 만들기</a>와 <a href="#Fragment">기본 설정
138프래그먼트 사용하기</a>에 관련된 섹션에서 논합니다.</p>
139
140
141<h3 id="SettingTypes">기본 설정</h3>
142
143<p>앱에 대한 설정은 모두 {@link
144android.preference.Preference} 클래스의 특정 하위 클래스로 표현됩니다. 각 하위 클래스에 핵심 속성이 한 세트씩 포함되어 있어
145설정의 제목과 기본 값 등과 같은 것을 지정할 수 있게 해줍니다. 각 하위 클래스는 또한 자신만의
146특수 속성과 사용자 인터페이스도 제공합니다. 예를 들어, 그림 1에서는 메시지 앱의 설정에서
147가져온 스크린샷을 나타낸 것입니다. 설정 화면에 있는 각 목록 항목은 각기 서로 다른 {@link
148android.preference.Preference} 객체로 지원됩니다.</p>
149
150<p>가장 보편적인 기본 설정을 몇 가지만 소개하면 다음과 같습니다.</p>
151
152<dl>
153  <dt>{@link android.preference.CheckBoxPreference}</dt>
154  <dd>활성화되었거나 비활성화된 설정에 대한 확인란이 있는 항목을 표시합니다. 저장된 값은
155부울입니다(확인란이 선택된 경우 <code>true</code>).</dd>
156
157  <dt>{@link android.preference.ListPreference}</dt>
158  <dd>무선 버튼 목록이 있는 대화를 엽니다. 저장된 값은
159지원되는 값 유형(위에 목록으로 나열) 중 어느 것이라도 될 수 있습니다.</dd>
160
161  <dt>{@link android.preference.EditTextPreference}</dt>
162  <dd>{@link android.widget.EditText} 위젯이 있는 대화를 엽니다. 저장된 값은 {@link
163java.lang.String}입니다.</dd>
164</dl>
165
166<p>다른 모든 하위 클래스와 이에 상응하는 속성의 목록을 보려면 {@link android.preference.Preference}
167 클래스를 참조하십시오.</p>
168
169<p>물론 기본 제공 클래스만으로는 필요한 것을 모두 충족할 수 없고 앱에 무언가 좀 더 특수한 것이
170필요할 수도 있습니다. 예를 들어 플랫폼은 현재 숫자나 날짜를 선택할 수 있는 {@link
171android.preference.Preference} 클래스를 제공하지 않습니다. 따라서 개발자 나름대로
172{@link android.preference.Preference} 하위 클래스를 정의해야 할 수도 있습니다. 이 작업을 수행하는 데 유용한 내용인 <a href="#Custom">사용자 지정 기본 설정 구축하기</a>에 관한 섹션을 참조하십시오.</p>
173
174
175
176<h2 id="DefiningPrefs">XML로 기본 설정 정의하기</h2>
177
178<p>새로운 {@link android.preference.Preference} 객체를 런타임에 인스턴트화하는 것도 가능하지만,
179설정 목록을 정의할 때에는 {@link android.preference.Preference}
180객체의 계층과 함께 XML을 사용해야 합니다. 설정 컬렉션을 정의하는 데 XM 파일을 사용하는 것이 선호되는 이유는 이 파일이
181읽기 쉬운 구조를 제공하여 업데이트가 단순하기 때문입니다. 또한, 앱의 설정은 보통
182미리 정의되어 있습니다. 다만 개발자도 여전히 런타임에 설정 컬렉션을 수정할 수 있습니다.</p>
183
184<p>각 {@link android.preference.Preference} 하위 클래스는 클래스 이름에 일치하는 XML 요소로
185선언하면 됩니다. 예를 들면 {@code &lt;CheckBoxPreference&gt;}가 이에 해당됩니다.</p>
186
187<p>이 XML 파일은 반드시 {@code res/xml/} 디렉터리에 저장해야 합니다. 파일의 이름은 무엇이든 원하는 대로 지정할 수 있지만,
188일반적으로는 {@code preferences.xml}이라고 명명합니다. 파일은 하나만 필요한 것이 보통입니다.
189왜냐하면 계층에 있는 분기(자신만의 설정 목록을 엶)는
190{@link android.preference.PreferenceScreen}의 중첩된 인스턴스를 사용하여 선언되기 때문입니다.</p>
191
192<p class="note"><strong>참고:</strong> 설정에 다중 창 레이아웃을 만들고자 하는 경우,
193각 프래그먼트에 대해 별도의 XML 파일이 필요합니다.</p>
194
195<p>XML 파일의 루트 노드는 반드시 {@link android.preference.PreferenceScreen
196&lt;PreferenceScreen&gt;} 요소여야 합니다. 바로 이 요소 내에 각 {@link
197android.preference.Preference}를 추가하는 것입니다.
198{@link android.preference.PreferenceScreen &lt;PreferenceScreen&gt;} 요소 내에 추가하는 각 하위는 설정 목록에서
199각기 항목 하나씩으로 나타납니다.</p>
200
201<p>예:</p>
202
203<pre>
204&lt;?xml version="1.0" encoding="utf-8"?>
205&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
206    &lt;CheckBoxPreference
207        android:key="pref_sync"
208        android:title="@string/pref_sync"
209        android:summary="@string/pref_sync_summ"
210        android:defaultValue="true" />
211    &lt;ListPreference
212        android:dependency="pref_sync"
213        android:key="pref_syncConnectionType"
214        android:title="@string/pref_syncConnectionType"
215        android:dialogTitle="@string/pref_syncConnectionType"
216        android:entries="@array/pref_syncConnectionTypes_entries"
217        android:entryValues="@array/pref_syncConnectionTypes_values"
218        android:defaultValue="@string/pref_syncConnectionTypes_default" />
219&lt;/PreferenceScreen>
220</pre>
221
222<p>이 예시에서는 {@link android.preference.CheckBoxPreference}와 {@link
223android.preference.ListPreference}가 하나씩 있습니다. 두 항목 모두 다음과 같은 세 가지 속성을 포함하고 있습니다.</p>
224
225<dl>
226  <dt>{@code android:key}</dt>
227  <dd>이 속성은 데이터 값을 유지하는 기본 설정에 필수입니다. 이것은 고유키(문자)를
228나타내며, 시스템이 이것을 사용하여 이 설정의 값을 {@link
229android.content.SharedPreferences}에 저장합니다.
230  <p>이 속성이 <em>필요하지 않은</em> 인스턴스는 기본 설정이
231{@link android.preference.PreferenceCategory} 또는 {@link android.preference.PreferenceScreen}인 경우, 또는
232기본 설정이 {@link android.content.Intent}를 호출할 것을 나타내거나(<a href="#Intents">{@code &lt;intent&gt;}</a> 요소로) {@link android.app.Fragment}를 표시하도록 지정하는 경우(<a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
233android:fragment}</a> 속성으로)뿐입니다.</p>
234  </dd>
235  <dt>{@code android:title}</dt>
236  <dd>이것은 설정에 대하여 사용자가 볼 수 있는 이름을 제공합니다.</dd>
237  <dt>{@code android:defaultValue}</dt>
238  <dd>이것은 시스템이 {@link
239android.content.SharedPreferences} 파일에 설정해야 하는 초기 값을 나타냅니다. 모든 설정에 기본 값을 제공해야
240합니다.</dd>
241</dl>
242
243<p>다른 모든 지원되는 속성에 대해서는 {@link
244android.preference.Preference}(및 각각의 하위 클래스) 관련 문서를 참조하십시오.</p>
245
246
247<div class="figure" style="width:300px">
248  <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" />
249  <p class="img-caption"><strong>그림 2.</strong> 제목이 있는 설정
250카테고리입니다. <br/><b>1.</b> 카테고리는 {@link
251android.preference.PreferenceCategory &lt;PreferenceCategory&gt;} 요소가 지정합니다. <br/><b>2.</b> 제목은
252{@code android:title} 속성으로 지정합니다.</p>
253</div>
254
255
256<p>설정 목록이 약 10개 항목을 초과하면 제목을 추가하여
257설정 그룹을 정의하거나, 해당 그룹을 별도의
258화면에 표시하는 것이 좋을 수도 있습니다. 이러한 옵션은 다음 섹션에 설명되어 있습니다.</p>
259
260
261<h3 id="Groups">설정 그룹 만들기</h3>
262
263<p>10개 이상의 설정 목록을 제시하는 경우, 사용자가
264이들을 둘러보고 이해하며 처리하는 데 어려움을 겪을 수 있습니다. 이 문제를 해결하려면
265설정의 일부 또는 모두를 그룹으로 나누어 사실상 하나의 긴 목록을 여러 개의 더 짧은 목록으로
266바꿔주면 됩니다. 관련된 설정 그룹 하나를 나타낼 때에는 다음과 같은 두 가지 방식 중 하나를 택하면 됩니다.</p>
267
268<ul>
269  <li><a href="#Titles">제목 사용하기</a></li>
270  <li><a href="#Subscreens">보조 화면 사용하기</a></li>
271</ul>
272
273<p>이와 같은 그룹화 기법 중 하나 또는 둘 모두를 사용하여 앱의 설정을 조직화할 수 있습니다. 어느 것을
274사용할지, 설정을 어떻게 나눌지 결정할 때에는 Android
275디자인의 <a href="{@docRoot}design/patterns/settings.html">설정</a> 가이드에 있는 지침을 따라야 합니다.</p>
276
277
278<h4 id="Titles">제목 사용하기</h4>
279
280<p>여러 개의 설정 그룹 사이에 구분선과 제목을 제공하고자 하는 경우(그림 2에 표시된 것과 같이),
281각 {@link android.preference.Preference} 객체 그룹을 {@link
282android.preference.PreferenceCategory} 내부에 배치합니다.</p>
283
284<p>예:</p>
285
286<pre>
287&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
288    &lt;PreferenceCategory
289        android:title="&#64;string/pref_sms_storage_title"
290        android:key="pref_key_storage_settings">
291        &lt;CheckBoxPreference
292            android:key="pref_key_auto_delete"
293            android:summary="&#64;string/pref_summary_auto_delete"
294            android:title="&#64;string/pref_title_auto_delete"
295            android:defaultValue="false"... />
296        &lt;Preference
297            android:key="pref_key_sms_delete_limit"
298            android:dependency="pref_key_auto_delete"
299            android:summary="&#64;string/pref_summary_delete_limit"
300            android:title="&#64;string/pref_title_sms_delete"... />
301        &lt;Preference
302            android:key="pref_key_mms_delete_limit"
303            android:dependency="pref_key_auto_delete"
304            android:summary="&#64;string/pref_summary_delete_limit"
305            android:title="&#64;string/pref_title_mms_delete" ... />
306    &lt;/PreferenceCategory>
307    ...
308&lt;/PreferenceScreen>
309</pre>
310
311
312<h4 id="Subscreens">보조 화면 사용하기</h4>
313
314<p>설정 그룹 여러 개를 보조 화면에 배치하고자 하는 경우(그림 3에 표시된 것과 같이), 해당
315{@link android.preference.Preference} 객체 그룹을 {@link
316android.preference.PreferenceScreen} 안에 배치합니다.</p>
317
318<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" />
319<p class="img-caption"><strong>그림 3.</strong> 설정 보조 화면입니다. {@code
320&lt;PreferenceScreen&gt;} 요소가
321항목을 만들며, 이 항목이 선택되면 별도의 목록이 열려 중첩된 설정을 표시합니다.</p>
322
323<p>예:</p>
324
325<pre>
326&lt;PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
327    &lt;!-- opens a subscreen of settings -->
328    &lt;PreferenceScreen
329        android:key="button_voicemail_category_key"
330        android:title="&#64;string/voicemail"
331        android:persistent="false">
332        &lt;ListPreference
333            android:key="button_voicemail_provider_key"
334            android:title="&#64;string/voicemail_provider" ... />
335        &lt;!-- opens another nested subscreen -->
336        &lt;PreferenceScreen
337            android:key="button_voicemail_setting_key"
338            android:title="&#64;string/voicemail_settings"
339            android:persistent="false">
340            ...
341        &lt;/PreferenceScreen>
342        &lt;RingtonePreference
343            android:key="button_voicemail_ringtone_key"
344            android:title="&#64;string/voicemail_ringtone_title"
345            android:ringtoneType="notification" ... />
346        ...
347    &lt;/PreferenceScreen>
348    ...
349&lt;/PreferenceScreen>
350</pre>
351
352
353<h3 id="Intents">인텐트 사용하기</h3>
354
355<p>어떤 경우에는 기본 설정 항목을 사용하여 설정 화면 대신 여러 가지 액티비티를
356열고자 할 수도 있습니다. 예를 들어 웹 브라우저를 열어 웹 페이지를 보는 것이 이에 해당됩니다. 사용자가 기본 설정 항목을 선택할 때 {@link
357android.content.Intent}를 호출하도록 하려면, {@code &lt;intent&gt;}
358요소를 상응하는 {@code &lt;Preference&gt;} 요소의 하위로 추가하면 됩니다.</p>
359
360<p>예를 들어 다음은 기본 설정 항목을 사용하여 웹 페이지를 열도록 하는 방법입니다.</p>
361
362<pre>
363&lt;Preference android:title="@string/prefs_web_page" >
364    &lt;intent android:action="android.intent.action.VIEW"
365            android:data="http://www.example.com" />
366&lt;/Preference>
367</pre>
368
369<p>다음 속성을 사용하여 명시적 인텐트와 암시적 인텐트 두 가지를 모두 만들 수 있습니다.</p>
370
371<dl>
372  <dt>{@code android:action}</dt>
373    <dd>할당할 작업이며, {@link android.content.Intent#setAction setAction()}
374메서드를 따릅니다.</dd>
375  <dt>{@code android:data}</dt>
376    <dd>할당할 데이터이며, {@link android.content.Intent#setData setData()} 메서드를 따릅니다.</dd>
377  <dt>{@code android:mimeType}</dt>
378    <dd>할당할 MIME 유형이며, {@link android.content.Intent#setType setType()}
379메서드를 따릅니다.</dd>
380  <dt>{@code android:targetClass}</dt>
381    <dd>구성 요소 이름의 클래스 부분이며, {@link android.content.Intent#setComponent
382setComponent()} 메서드를 따릅니다.</dd>
383  <dt>{@code android:targetPackage}</dt>
384    <dd>구성 요소 이름의 패키지 부분이며, {@link
385android.content.Intent#setComponent setComponent()} 메서드를 따릅니다.</dd>
386</dl>
387
388
389
390<h2 id="Activity">기본 설정 액티비티 만들기</h2>
391
392<p>설정을 액티비티에서 표시하려면 {@link
393android.preference.PreferenceActivity} 클래스를 확장하면 됩니다. 이것은 일반적인 {@link
394android.app.Activity} 클래스 확장의 일종입니다. 이는 {@link
395android.preference.Preference} 객체의 계층에 기반한 설정 목록을 표시합니다. {@link android.preference.PreferenceActivity}는
396사용자가 변경 작업을 하면 각 {@link
397android.preference.Preference}와 연관된 설정을 유지합니다.</p>
398
399<p class="note"><strong>참고:</strong> Android 3.0 이상에 맞춰 애플리케이션을 개발하는 경우,
400대신 {@link android.preference.PreferenceFragment}를 사용해야 합니다. 다음 섹션의
401<a href="#Fragment">기본 설정 프래그먼트 사용하기</a> 관련 내용을 참조하십시오.</p>
402
403<p>여기서 기억해야 할 가장 중요한 점은 {@link
404android.preference.PreferenceActivity#onCreate onCreate()} 콜백 중에 보기 레이아웃을 로딩해서는 안 된다는 것입니다. 그 대신 {@link
405android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()}를 호출하여
406XML 파일에서 선언한 기본 설정을 액티비티에 추가합니다. 예를 들어 다음은 기능적인
407{@link android.preference.PreferenceActivity}에 필요한 가장 최소한의 코드를 나타낸 것입니다.</p>
408
409<pre>
410public class SettingsActivity extends PreferenceActivity {
411    &#64;Override
412    public void onCreate(Bundle savedInstanceState) {
413        super.onCreate(savedInstanceState);
414        addPreferencesFromResource(R.xml.preferences);
415    }
416}
417</pre>
418
419<p>사실 이 코드만으로 몇몇 앱에는 충분합니다. 사용자가 기본 설정을 수정하자마자
420시스템이 해당 변경을 기본 {@link android.content.SharedPreferences} 파일에 저장하여,
421사용자의 설정을 확인해야 할 때 다른 애플리케이션 구성 요소가 이를 읽을 수 있도록 하기 때문입니다. 하지만
422대다수의 앱은 기본 설정에 일어나는 변경을 수신 대기하기 위해 약간의 코드가 더 필요합니다.
423{@link android.content.SharedPreferences} 파일에 일어나는 변경을 수신 대기하는 데 관한
424자세한 정보는 <a href="#ReadingPrefs">기본 설정 읽기</a>에 관한 섹션을 참조하십시오.</p>
425
426
427
428
429<h2 id="Fragment">기본 설정 프래그먼트 사용하기</h2>
430
431<p>Android 3.0(API 레벨 11) 이상에 맞춰 개발하는 경우, {@link
432android.preference.PreferenceFragment}를 사용하여 {@link android.preference.Preference}
433객체 목록을 표시해야 합니다. {@link android.preference.PreferenceFragment}는 모든 액티비티에 추가할 수 있습니다. 즉,
434{@link android.preference.PreferenceActivity}를 사용하지 않아도 됩니다.</p>
435
436<p><a href="{@docRoot}guide/components/fragments.html">프래그먼트</a>는 액티비티만
437사용하는 것에 비해 애플리케이션에 보다 유연한 아키텍처를 제공하며, 이는 구축하는
438액티비티의 종류와 무관하게 적용됩니다. 따라서 설정 표시를 제어하는 데에는 {@link
439android.preference.PreferenceFragment}를 {@link
440android.preference.PreferenceActivity} 대신 사용하는 방안을 권장합니다(가능한 경우).</p>
441
442<p>{@link android.preference.PreferenceFragment} 구현은 매우 간단합니다.
443{@link android.preference.PreferenceFragment#onCreate onCreate()} 메서드를 정의하여 기본 설정 파일을
444{@link android.preference.PreferenceFragment#addPreferencesFromResource
445addPreferencesFromResource()}로 로딩하도록 하기만 하면 됩니다. 예:</p>
446
447<pre>
448public static class SettingsFragment extends PreferenceFragment {
449    &#64;Override
450    public void onCreate(Bundle savedInstanceState) {
451        super.onCreate(savedInstanceState);
452
453        // Load the preferences from an XML resource
454        addPreferencesFromResource(R.xml.preferences);
455    }
456    ...
457}
458</pre>
459
460<p>그런 다음 이 프래그먼트를 {@link android.app.Activity}에 추가하기만 하면 되고, 이는 다른 모든
461{@link android.app.Fragment}에서와 마찬가지입니다. 예:</p>
462
463<pre>
464public class SettingsActivity extends Activity {
465    &#64;Override
466    protected void onCreate(Bundle savedInstanceState) {
467        super.onCreate(savedInstanceState);
468
469        // Display the fragment as the main content.
470        getFragmentManager().beginTransaction()
471                .replace(android.R.id.content, new SettingsFragment())
472                .commit();
473    }
474}
475</pre>
476
477<p class="note"><strong>참고:</strong> {@link android.preference.PreferenceFragment}에는 자신만의
478{@link android.content.Context} 객체가 없습니다. {@link android.content.Context}
479객체가 필요한 경우, {@link android.app.Fragment#getActivity()}를 호출하면 됩니다. 하지만,
480{@link android.app.Fragment#getActivity()}를 호출하는 것은 프래그먼트가 액티비티에 첨부되어 있는 경우만으로 국한시켜야 한다는 점을 유의하십시오. 프래그먼트가
481아직 첨부되지 않았거나 수명 주기가 끝날 무렵 분리된 경우, {@link
482android.app.Fragment#getActivity()}가 null을 반환합니다.</p>
483
484
485<h2 id="Defaults">설정 기본 값</h2>
486
487<p>여러분이 만드는 기본 설정은 애플리케이션에 중요한 동작을 정의하는 경우가 많을 것입니다. 따라서
488연관된 {@link android.content.SharedPreferences} 파일을
489각 {@link android.preference.Preference}에 대한 기본 값으로 초기화하여 사용자가 애플리케이션을 처음 열 때
490적용하는 것이 중요합니다.</p>
491
492<p>가장 먼저 해야 할 일은 XML 파일 내의 각 {@link
493android.preference.Preference}
494객체에 대해 기본 값을 지정하는 것입니다. 이때 {@code android:defaultValue} 속성을 사용합니다. 이 값은 상응하는
495{@link android.preference.Preference} 객체에 대해 적절한 어느 데이터 유형이라도 될 수 있습니다. 예:
496</p>
497
498<pre>
499&lt;!-- default value is a boolean -->
500&lt;CheckBoxPreference
501    android:defaultValue="true"
502    ... />
503
504&lt;!-- default value is a string -->
505&lt;ListPreference
506    android:defaultValue="@string/pref_syncConnectionTypes_default"
507    ... />
508</pre>
509
510<p>그런 다음, 애플리케이션의 기본 액티비티에 있는 {@link android.app.Activity#onCreate onCreate()}
511메서드로부터&mdash;또한 사용자가 애플리케이션에 처음으로 들어올 통로가 될 수 있는
512다른 모든 액티비티도 포함&mdash;{@link android.preference.PreferenceManager#setDefaultValues
513setDefaultValues()}를 호출합니다.</p>
514
515<pre>
516PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
517</pre>
518
519<p>이것을 {@link android.app.Activity#onCreate onCreate()} 중에 호출하면
520애플리케이션이 기본 설정으로 적절히 초기화되도록 보장할 수 있습니다. 이것은 애플리케이션이
521몇 가지 동작을 결정하기 위해 읽어야 할 수도 있습니다(예를 들어 셀룰러 네트워크에서 데이터를
522다운로드할지 여부 등).</p>
523
524<p>이 메서드는 다음과 같은 세 개의 인수를 취합니다.</p>
525<ul>
526  <li>애플리케이션 {@link android.content.Context}.</li>
527  <li>기본 값을 설정하고자 하는 기본 설정 XML 파일에 대한 리소스 ID입니다.</li>
528  <li>기본 값을 한 번 이상 설정해야 하는지 여부를 나타내는 부울 값입니다.
529<p><code>false</code>인 경우, 시스템은 이 메서드가 전에 한 번도 호출된 적이 없을 경우에만
530기본 값을 설정합니다(아니면 기본 값을 공유한 기본 설정 파일에 있는 {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
531가 안전합니다).</p></li>
532</ul>
533
534<p>세 번째 인수를 <code>false</code>로 설정해 두는 한 이 메서드를 액티비티가 시작될 때마다
535안전하게 호출할 수 있으며, 그렇게 해도 사용자의 저장된 기본 설정을 기본값으로 초기화하여
536재정의하지 않습니다. 하지만 이를 <code>true</code>로 설정하면, 이전의 모든 값을
537기본 값으로 재정의하게 됩니다.</p>
538
539
540
541<h2 id="PreferenceHeaders">기본 설정 헤더 사용하기</h2>
542
543<p>드문 경우지만 설정을 디자인할 때 첫 화면에는
544<a href="#Subscreens">보조 화면</a> 목록만 표시하도록 하고자 할 수도 있습니다(예: 시스템 설정 앱,
545그림 4와 5 참조). 그러한 디자인을 Android 3.0 이상을 대상으로 개발하는 경우, Android 3.0에 있는
546새로운 "헤더" 기능을 사용해야 합니다. 이것이 중첩된
547{@link android.preference.PreferenceScreen} 요소를 사용하여 보조 화면을 구축하는 방안을 대신합니다.</p>
548
549<p>헤더를 사용하여 설정을 구축하려면 다음과 같이 해야 합니다.</p>
550<ol>
551  <li>각 설정 그룹을 별개의 {@link
552android.preference.PreferenceFragment} 인스턴스로 구분합니다. 다시 말해, 설정 그룹마다 별도의 XML 파일이 하나씩 있어야 한다는
553뜻입니다.</li>
554  <li>각 설정 그룹을 목록으로 나열하는 XML 헤더 파일을 생성하고 어느 프래그먼트에
555상응하는 설정 목록이 들어있는지 선언합니다.</li>
556  <li>{@link android.preference.PreferenceActivity} 클래스를 확장하여 설정을 호스팅하도록 합니다.</li>
557  <li>{@link
558android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} 콜백을 구현하여 헤더 파일을
559나타냅니다.</li>
560</ol>
561
562<p>이 디자인을 사용하는 데 있어 커다란 이점은 {@link android.preference.PreferenceActivity}가
563(앱이) 대형 화면에서 실행될 때 그림 4에서 나타낸 것과 같이 창 두 개짜리 레이아웃을 자동으로 표시한다는 것입니다.</p>
564
565<p>애플리케이션이 Android 3.0 이전 버전을 지원한다 하더라도 애플리케이션이
566{@link android.preference.PreferenceFragment}를 사용하여
567신형 기기에서 창 두 개짜리 표시를 지원하도록 하면서도 구형 기기에서는 일반적인 다중 화면 계층을
568여전히 지원하도록 할 수도 있습니다(<a href="#BackCompatHeaders">기본 설정 헤더로
569이전 버전 지원하기</a>를 참조하십시오).</p>
570
571<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
572<p class="img-caption"><strong>그림 4.</strong> 헤더가 있는 창 두 개짜리 레이아웃입니다. <br/><b>1.</b> 헤더는
573XML 헤더 파일로 정의됩니다. <br/><b>2.</b> 각 설정 그룹은
574{@link android.preference.PreferenceFragment}가 정의하며, 이는 헤더 파일에 있는 {@code &lt;header&gt;} 요소가
575지정합니다.</p>
576
577<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" />
578<p class="img-caption"><strong>그림 5.</strong> 설정 헤더가 있는 핸드셋 기기입니다. 항목을 선택하면
579연관된 {@link android.preference.PreferenceFragment}가 헤더를
580대체합니다.</p>
581
582
583<h3 id="CreateHeaders" style="clear:left">헤더 파일 만들기</h3>
584
585<p>헤더 목록에 있는 각 설정 그룹은 루트 {@code &lt;preference-headers&gt;}
586요소 안에 있는 {@code &lt;header&gt;} 요소 하나로 나타냅니다. 예:</p>
587
588<pre>
589&lt;?xml version="1.0" encoding="utf-8"?>
590&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
591    &lt;header
592        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
593        android:title="@string/prefs_category_one"
594        android:summary="@string/prefs_summ_category_one" />
595    &lt;header
596        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
597        android:title="@string/prefs_category_two"
598        android:summary="@string/prefs_summ_category_two" >
599        &lt;!-- key/value pairs can be included as arguments for the fragment. -->
600        &lt;extra android:name="someKey" android:value="someHeaderValue" />
601    &lt;/header>
602&lt;/preference-headers>
603</pre>
604
605<p>각 헤더는 {@code android:fragment} 속성으로 {@link
606android.preference.PreferenceFragment} 예를 선언하며 이는 사용자가 헤더를 선택하면 열려야 합니다.</p>
607
608<p>{@code &lt;extras&gt;} 요소를 사용하면 키-값 쌍을 {@link
609android.os.Bundle} 내의 프래그먼트에 전달할 수 있게 해줍니다. 이 프래그먼트가 인수를 검색하려면 {@link
610android.app.Fragment#getArguments()}를 호출하면 됩니다. 인수를 프래그먼트에 전달하는 데에는 여러 가지 이유가 있을 수 있지만,
611한 가지 중요한 이유를 예로 들면 각 그룹에 대해 {@link
612android.preference.PreferenceFragment}의 같은 하위 클래스를 재사용하고, 이 인수를 사용하여 해당 프래그먼트가 로딩해야 하는
613기본 설정 XML 파일이 무엇인지 나타낼 수 있다는 점입니다.</p>
614
615<p>예를 들어 다음은 여러 가지 설정 그룹에 재사용할 수 있는 프래그먼트입니다. 이것은
616각 헤더가 {@code "settings"} 키로 {@code &lt;extra&gt;} 인수를 정의하는 경우를 나타낸 것입니다.</p>
617
618<pre>
619public static class SettingsFragment extends PreferenceFragment {
620    &#64;Override
621    public void onCreate(Bundle savedInstanceState) {
622        super.onCreate(savedInstanceState);
623
624        String settings = getArguments().getString("settings");
625        if ("notifications".equals(settings)) {
626            addPreferencesFromResource(R.xml.settings_wifi);
627        } else if ("sync".equals(settings)) {
628            addPreferencesFromResource(R.xml.settings_sync);
629        }
630    }
631}
632</pre>
633
634
635
636<h3 id="DisplayHeaders">헤더 표시하기</h3>
637
638<p>기본 설정 헤더를 표시하려면 {@link
639android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} 콜백 메서드를 구현하고
640{@link android.preference.PreferenceActivity#loadHeadersFromResource
641loadHeadersFromResource()}를 호출해야 합니다. 예:</p>
642
643<pre>
644public class SettingsActivity extends PreferenceActivity {
645    &#64;Override
646    public void onBuildHeaders(List&lt;Header> target) {
647        loadHeadersFromResource(R.xml.preference_headers, target);
648    }
649}
650</pre>
651
652<p>사용자가 헤더 목록에서 항목을 하나 선택하면 시스템이 연관된 {@link
653android.preference.PreferenceFragment}를 엽니다.</p>
654
655<p class="note"><strong>참고:</strong> 기본 설정 헤더를 사용하는 경우, {@link
656android.preference.PreferenceActivity}의 하위 클래스가 {@link
657android.preference.PreferenceActivity#onCreate onCreate()} 메서드를 구현하지 않아도 됩니다. 액티비티에 대한 필수 작업은
658헤더를 로딩하는 것뿐이기 때문입니다.</p>
659
660
661<h3 id="BackCompatHeaders">기본 설정 헤더로 이전 버전 지원하기</h3>
662
663<p>애플리케이션이 Android 3.0 이전 버전을 지원하는 경우에도 여전히 헤더를 사용하여
664Android 3.0 이상에서 창 두 개짜리 레이아웃을 제공하도록 할 수 있습니다. 개발자가 해야 할 일은 추가로 기본 설정 XML 파일을
665생성하는 것뿐입니다. 이 파일은 마치 헤더 항목처럼 동작하는 기본적인 {@link android.preference.Preference
666&lt;Preference&gt;} 요소를 사용합니다(이것을 이전 Android 버전이 사용하도록
667할 예정).</p>
668
669<p>하지만 새로운 {@link android.preference.PreferenceScreen}을 여는 대신 각 {@link
670android.preference.Preference &lt;Preference&gt;} 요소가 {@link android.content.Intent}를 하나씩
671{@link android.preference.PreferenceActivity}에 전송합니다. 이것이 로딩할 XML 파일이 무엇인지를
672나타냅니다.</p>
673
674<p>예를 들어 다음은 Android 3.0 이상에서 사용되는 기본 설정 헤더에 대한
675XML 파일입니다({@code res/xml/preference_headers.xml}).</p>
676
677<pre>
678&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
679    &lt;header
680        android:fragment="com.example.prefs.SettingsFragmentOne"
681        android:title="@string/prefs_category_one"
682        android:summary="@string/prefs_summ_category_one" />
683    &lt;header
684        android:fragment="com.example.prefs.SettingsFragmentTwo"
685        android:title="@string/prefs_category_two"
686        android:summary="@string/prefs_summ_category_two" />
687&lt;/preference-headers>
688</pre>
689
690<p>그리고 다음은, Android 3.0 이전 버전에 같은 헤더를 제공하는 기본 설정
691파일입니다({@code res/xml/preference_headers_legacy.xml}).</p>
692
693<pre>
694&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
695    &lt;Preference
696        android:title="@string/prefs_category_one"
697        android:summary="@string/prefs_summ_category_one"  >
698        &lt;intent
699            android:targetPackage="com.example.prefs"
700            android:targetClass="com.example.prefs.SettingsActivity"
701            android:action="com.example.prefs.PREFS_ONE" />
702    &lt;/Preference>
703    &lt;Preference
704        android:title="@string/prefs_category_two"
705        android:summary="@string/prefs_summ_category_two" >
706        &lt;intent
707            android:targetPackage="com.example.prefs"
708            android:targetClass="com.example.prefs.SettingsActivity"
709            android:action="com.example.prefs.PREFS_TWO" />
710    &lt;/Preference>
711&lt;/PreferenceScreen>
712</pre>
713
714<p>{@code &lt;preference-headers&gt;}에 대한 지원이 Android 3.0에서 추가되었기 때문에 시스템이
715{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()}를 {@link
716android.preference.PreferenceActivity}에서 호출하는 것은 Android 3.0 이상에서 실행될 때뿐입니다. "레거시" 헤더 파일을
717로딩하려면({@code preference_headers_legacy.xml}) 반드시 Android
718버전을 확인해야 하며, 해당 버전이 Android 3.0 이전인 경우({@link
719android.os.Build.VERSION_CODES#HONEYCOMB}), {@link
720android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()}를 호출하여
721레거시 헤더 파일을 로딩해야 합니다. 예:</p>
722
723<pre>
724&#64;Override
725public void onCreate(Bundle savedInstanceState) {
726    super.onCreate(savedInstanceState);
727    ...
728
729    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
730        // Load the legacy preferences headers
731        addPreferencesFromResource(R.xml.preference_headers_legacy);
732    }
733}
734
735// Called only on Honeycomb and later
736&#64;Override
737public void onBuildHeaders(List&lt;Header> target) {
738   loadHeadersFromResource(R.xml.preference_headers, target);
739}
740</pre>
741
742<p>이제 남은 할 일이라고는 {@link android.content.Intent}를 처리하는 것뿐입니다. 이것은
743액티비티로 전달되어 어느 기본 설정 파일을 로딩해야 하는지 식별하는 데 쓰입니다. 그럼 이제 인텐트의 작업을 검색하여 기본 설정 XML의
744{@code &lt;intent&gt;} 태그에서 사용한 알려진 작업 문자열에 비교해보겠습니다.</p>
745
746<pre>
747final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
748...
749
750&#64;Override
751public void onCreate(Bundle savedInstanceState) {
752    super.onCreate(savedInstanceState);
753
754    String action = getIntent().getAction();
755    if (action != null &amp;&amp; action.equals(ACTION_PREFS_ONE)) {
756        addPreferencesFromResource(R.xml.preferences);
757    }
758    ...
759
760    else if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
761        // Load the legacy preferences headers
762        addPreferencesFromResource(R.xml.preference_headers_legacy);
763    }
764}
765</pre>
766
767<p>{@link
768android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()}를 연이어 호출하면
769모든 기본 설정을 하나의 목록에 쌓게 된다는 점을 유의하십시오. 따라서 이것은 'Else-if' 문이 있는 조건을 변경하여 딱 한 번만
770호출하도록 주의해야 합니다.</p>
771
772
773
774
775
776<h2 id="ReadingPrefs">기본 설정 읽기</h2>
777
778<p>기본적으로 앱의 기본 설정은 모두
779애플리케이션 내의 어디서든 정적 메서드 {@link
780android.preference.PreferenceManager#getDefaultSharedPreferences
781PreferenceManager.getDefaultSharedPreferences()}를 호출하면 액세스할 수 있는 파일에 저장됩니다. 이것은 {@link
782android.content.SharedPreferences} 객체를 반환하며, 여기에 {@link
783android.preference.PreferenceActivity}에서 사용한 {@link android.preference.Preference} 객체와
784연관된 모든 키-값 쌍이 들어있습니다.</p>
785
786<p>예를 들어 다음은 기본 설정 값 중 하나를 애플리케이션 내의 다른 모든 액티비티에서 읽는 방법을
787나타낸 것입니다.</p>
788
789<pre>
790SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
791String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
792</pre>
793
794
795
796<h3 id="Listening">기본 설정 변경 수신 대기</h3>
797
798<p>사용자가 기본 설정 중 하나를 변경하자마자 이에 대해 알림을 받는 것이 좋은 데에는 몇 가지
799이유가 있습니다. 기본 설정 중 어느 하나에라도 변경이 발생했을 때 콜백을 받으려면,
800{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
801SharedPreference.OnSharedPreferenceChangeListener} 인터페이스를 구현하고
802{@link android.content.SharedPreferences} 객체에 대한 수신기를 등록합니다. 이때 {@link
803android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
804registerOnSharedPreferenceChangeListener()}를 호출하면 됩니다.</p>
805
806<p>이 인터페이스에는 콜백 메서드가 {@link
807android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged
808onSharedPreferenceChanged()} 하나뿐이며, 인터페이스를 액티비티의 일부분으로 구현하는 것이
809가장 쉬운 방법일 공산이 큽니다. 예:</p>
810
811<pre>
812public class SettingsActivity extends PreferenceActivity
813                              implements OnSharedPreferenceChangeListener {
814    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
815    ...
816
817    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
818        String key) {
819        if (key.equals(KEY_PREF_SYNC_CONN)) {
820            Preference connectionPref = findPreference(key);
821            // Set summary to be the user-description for the selected value
822            connectionPref.setSummary(sharedPreferences.getString(key, ""));
823        }
824    }
825}
826</pre>
827
828<p>이 예시에서 메서드는 변경된 설정이 알려진 기본 설정 키에 대한 것인지 여부를 확인합니다. 이것은
829{@link android.preference.PreferenceActivity#findPreference findPreference()}를 호출하여
830변경된 {@link android.preference.Preference} 객체를 가져오는데, 이렇게 해야 항목의 요약을 수정하여
831사용자의 선택에 대한 설명이 되도록 할 수 있습니다. 다시 말해, 설정이 {@link
832android.preference.ListPreference} 또는 다른 다중 선택 설정인 경우, 설정이 변경되어 현재 상태를 표시하도록 하면 {@link
833android.preference.Preference#setSummary setSummary()}를 호출해야 한다는 뜻입니다(예를 들어
834그림 5에 표시된 절전 모드 설정과 같음).</p>
835
836<p class="note"><strong>참고:</strong> Android 디자인 문서의 <a href="{@docRoot}design/patterns/settings.html">설정</a> 관련 내용에서 설명한 바와 같이, 사용자가 기본 설정을 변경할 때마다
837{@link android.preference.ListPreference}의 요약을 업데이트하는 것을 권장합니다. 이렇게 하여 현재 설정을
838나타내는 것입니다.</p>
839
840<p>액티비티에서 적절한 수명 주기 관리를 수행하려면
841{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener}를 등록하고 등록 해제하는 작업은 각각 {@link
842android.app.Activity#onResume} 및 {@link android.app.Activity#onPause} 콜백 중에 수행하는 것을 권장합니다.</p>
843
844<pre>
845&#64;Override
846protected void onResume() {
847    super.onResume();
848    getPreferenceScreen().getSharedPreferences()
849            .registerOnSharedPreferenceChangeListener(this);
850}
851
852&#64;Override
853protected void onPause() {
854    super.onPause();
855    getPreferenceScreen().getSharedPreferences()
856            .unregisterOnSharedPreferenceChangeListener(this);
857}
858</pre>
859
860<p class="caution"><strong>주의:</strong> {@link
861android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
862registerOnSharedPreferenceChangeListener()}를 호출하면
863현재의 경우, 기본 설정 관리자가 수신기에 대한 강력한 참조를 저장하지 않습니다. 반드시 수신기에 대한 강력한
864참조를 저장해야 합니다. 그렇지 않으면 가비지 수집의 대상이 될 가능성이 높습니다. 권장 사항으로는
865수신기를 객체의 인스턴스 데이터 안에 보관하는 것을 추천합니다. 이 객체는
866수신기를 필요로 하는 기간만큼 오래 존재할 것이 확실해야 합니다.</p>
867
868<p>예를 들어 다음 코드에서 발신자는 수신기에 대한 참조를
869보관하지 않습니다. 그 결과 해당 수신기가 가비지 수집의 대상이 되며
870향후 언젠가 알 수 없는 시점에 고장을 일으키게 될 것입니다.</p>
871
872<pre>
873prefs.registerOnSharedPreferenceChangeListener(
874  // Bad! The listener is subject to garbage collection!
875  new SharedPreferences.OnSharedPreferenceChangeListener() {
876  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
877    // listener implementation
878  }
879});
880</pre>
881
882<p>대신, 수신기에 대한 참조를 수신기가 필요한 기간만큼 오래 존재할 것이 확실한 객체의
883인스턴스 데이터 필드에 저장하십시오.</p>
884
885<pre>
886SharedPreferences.OnSharedPreferenceChangeListener listener =
887    new SharedPreferences.OnSharedPreferenceChangeListener() {
888  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
889    // listener implementation
890  }
891};
892prefs.registerOnSharedPreferenceChangeListener(listener);
893</pre>
894
895<h2 id="NetworkUsage">네트워크 사용량 관리하기</h2>
896
897
898<p>Android 4.0부터 시스템의 설정 애플리케이션을 사용하면 사용자가
899애플리케이션이 전경과 배경에 있는 동안 각각 얼마나 많은 네트워크 데이터를 사용하는지 알아볼 수 있게 되었습니다. 그런 다음
900사용자는 각각의 앱에 대해 배경 데이터 사용을 비활성화할 수 있습니다. 사용자가 여러분의 앱이 배경에서
901데이터에 액세스하는 기능을 비활성화하는 사태를 피하려면 데이터 연결을 효율적으로 사용하고
902사용자가 애플리케이션 설정을 통하여 앱의 데이터 사용량을 미세 조정할 수 있도록 허용해야 합니다.<p>
903
904<p>예를 들어 사용자에게 앱의 데이터 동기화 빈도를 제어하도록 허용할 수 있습니다. 앱이 Wi-Fi에 있을 때에만
905업로드/다운로드를 수행하도록 할지 여부, 앱이 로밍 중에 데이터를 사용하도록 할지 여부 등을 이렇게 조절합니다. 사용자가
906이러한 제어 기능을 사용할 수 있게 되면 시스템 설정에서 설정한 한도에 가까워지고
907있을 때 앱의 데이터 액세스를 비활성화할 가능성이 낮아집니다. 그 대신 앱이 사용하는 데이터 양을
908정밀하게 제어할 수 있기 때문입니다.</p>
909
910<p>일단 필요한 기본 설정을 {@link android.preference.PreferenceActivity}에
911추가하여 앱의 데이터 습관을 제어하도록 했으면, 다음으로 매니페스트 파일에 있는 {@link
912android.content.Intent#ACTION_MANAGE_NETWORK_USAGE}에 대한 인텐트 필터를 추가해야 합니다. 예:</p>
913
914<pre>
915&lt;activity android:name="SettingsActivity" ... >
916    &lt;intent-filter>
917       &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
918       &lt;category android:name="android.intent.category.DEFAULT" />
919    &lt;/intent-filter>
920&lt;/activity>
921</pre>
922
923<p>이 인텐트 필터는 이것이 애플리케이션의 데이터 사용량을 제어하는 액티비티라는
924사실을 시스템에 나타내는 역할을 합니다. 따라서, 사용자가 시스템의 설정 앱에서 여러분의 앱이
925얼마나 많은 데이터를 사용하는지 알아볼 때면 <em>애플리케이션 설정 보기</em> 버튼을 사용할 수 있어
926{@link android.preference.PreferenceActivity}를 시작하게 됩니다. 그러면 사용자는
927앱이 사용할 데이터 양을 미세하게 조정할 수 있습니다.</p>
928
929
930
931
932
933
934
935<h2 id="Custom">사용자 지정 기본 설정 구축하기</h2>
936
937<p>Android 프레임워크에는 다양한 {@link android.preference.Preference} 하위 클래스가 포함되어 있어
938여러 가지 설정 유형에 맞게 UI를 구축할 수 있습니다.
939하지만, 기본 제공 솔루션이 없는 설정이 필요하게 되는 경우도 있습니다. 예를 들어 숫자 선택기 또는
940날짜 선택기 등이 이에 해당됩니다. 그러한 경우에는 사용자 지정 기본 설정을 만들어야 합니다. 이때
941{@link android.preference.Preference} 클래스 또는 다른 하위 클래스 중 하나를 확장하는 방법을 씁니다.</p>
942
943<p>{@link android.preference.Preference} 클래스를 확장하는 경우, 다음과 같이
944몇 가지 중요한 해야 할 일이 있습니다.</p>
945
946<ul>
947  <li>사용자가 설정을 선택하면 나타나는 사용자 인터페이스를 지정합니다.</li>
948  <li>필요에 따라 설정의 값을 저장합니다.</li>
949  <li>{@link android.preference.Preference}가 보이게 되면
950이를 현재(또는 기본) 값으로 초기화합니다.</li>
951  <li>시스템이 요청하는 경우 기본 값을 제공합니다.</li>
952  <li>{@link android.preference.Preference}가 나름의 UI(예: 대화)를 제공하는 경우, 상태를
953저장하고 복원하여 수명 주기 변경을 처리할 수 있도록 합니다(예: 사용자가 화면을 돌리는 경우).</li>
954</ul>
955
956<p>다음 섹션에서는 이와 같은 각각의 작업을 수행하는 방법을 설명합니다.</p>
957
958
959
960<h3 id="CustomSelected">사용자 인터페이스 지정하기</h3>
961
962  <p>{@link android.preference.Preference} 클래스를 직접 확장하는 경우,
963{@link android.preference.Preference#onClick()}을 구현하여 사용자가
964항목을 선택할 때 일어날 동작을 정의해야 합니다. 그러나, 대부분의 사용자 지정 설정은 {@link android.preference.DialogPreference}를 확장하여
965대화를 표시하도록 합니다. 이렇게 하면 절차가 단순해집니다. {@link
966android.preference.DialogPreference}를 확장하는 경우에는 클래스 생성자 중에 반드시 {@link
967android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()}를 호출하여
968대화에 대한 레이아웃을 지정해야 합니다.</p>
969
970  <p>예를 들어 다음은 레이아웃을 선언하는 사용자 지정 {@link
971android.preference.DialogPreference}와 기본
972긍정적 및 부정적 대화 버튼에 대한 텍스트를 지정하는 생성자입니다.</p>
973
974<pre>
975public class NumberPickerPreference extends DialogPreference {
976    public NumberPickerPreference(Context context, AttributeSet attrs) {
977        super(context, attrs);
978
979        setDialogLayoutResource(R.layout.numberpicker_dialog);
980        setPositiveButtonText(android.R.string.ok);
981        setNegativeButtonText(android.R.string.cancel);
982
983        setDialogIcon(null);
984    }
985    ...
986}
987</pre>
988
989
990
991<h3 id="CustomSave">설정의 값 저장하기</h3>
992
993<p>설정에 대한 값은 언제든 저장할 수 있습니다. {@link
994android.preference.Preference} 클래스의 {@code persist*()} 메서드 중 하나를 호출하기만 하면 됩니다. 예를 들어 설정의 값이 정수인 경우 {@link
995android.preference.Preference#persistInt persistInt()}를, 부울을 저장하려면
996{@link android.preference.Preference#persistBoolean persistBoolean()}을 호출하십시오.</p>
997
998<p class="note"><strong>참고:</strong> 각각의 {@link android.preference.Preference}는 데이터 유형 하나씩만
999저장할 수 있으므로, 사용자 지정
1000{@link android.preference.Preference}에서 사용한 데이터 유형에 적절한 {@code persist*()} 메서드를 사용해야 합니다.</p>
1001
1002<p>설정을 유지하기로 선택하는 시점은 확장하는 지점이 {@link
1003android.preference.Preference} 클래스인지에 좌우될 수 있습니다. {@link
1004android.preference.DialogPreference}를 확장하면 값을 유지하는 것은 대화가 긍정적인 결과로 인해
1005닫히는 경우만으로 국한해야 합니다(사용자가 "확인(OK)" 버튼을 선택하는 경우).</p>
1006
1007<p>{@link android.preference.DialogPreference}가 닫히면 시스템이 {@link
1008android.preference.DialogPreference#onDialogClosed onDialogClosed()} 메서드를 호출합니다. 이 메서드에는
1009부울 인수가 포함되어 있어 사용자의 결과가 "긍정적"인지 아닌지를 나타냅니다. 이 값이
1010<code>true</code>인 경우, 사용자가 긍정적 버튼을 선택한 것이고 새 값을 저장해야 합니다. 예:
1011</p>
1012
1013<pre>
1014&#64;Override
1015protected void onDialogClosed(boolean positiveResult) {
1016    // When the user selects "OK", persist the new value
1017    if (positiveResult) {
1018        persistInt(mNewValue);
1019    }
1020}
1021</pre>
1022
1023<p>이 예시에서 <code>mNewValue</code>는 설정의 현재 값을 보유한 클래스
1024구성원입니다. {@link android.preference.Preference#persistInt persistInt()}를 호출하면
1025{@link android.content.SharedPreferences} 파일에 대한 값을 저장합니다(이
1026{@link android.preference.Preference}에 대하여 XML 파일에 지정된 키를 자동으로 사용합니다).</p>
1027
1028
1029<h3 id="CustomInitialize">현재 값 초기화하기</h3>
1030
1031<p>시스템이 {@link android.preference.Preference}를 화면에 추가하는 경우, 이는
1032{@link android.preference.Preference#onSetInitialValue onSetInitialValue()}를 호출하여
1033설정에 유지된 값이 있는지 없는지를 알립니다. 유지된 값이 없는 경우, 이 호출은 기본 값을
1034제공합니다.</p>
1035
1036<p>{@link android.preference.Preference#onSetInitialValue onSetInitialValue()} 메서드는
1037부울 값 <code>restorePersistedValue</code>를 전달하여 해당 설정에 대해 이미 어떤 값이 유지되었는지
1038아닌지를 나타냅니다. 만일 이것이 <code>true</code>라면, 유지된 값을 검색하되
1039{@link
1040android.preference.Preference} 클래스의 {@code getPersisted*()} 메서드 중 하나를 호출하는 방법을 써야 합니다. 예를 들어 정수 값이라면 {@link
1041android.preference.Preference#getPersistedInt getPersistedInt()}를 사용합니다. 보통은
1042유지된 값을 검색하여, UI에 이전에 저장된 값을 반영하여 이를 적절하게 업데이트할 수
1043있도록 하는 것이 좋습니다.</p>
1044
1045<p><code>restorePersistedValue</code>가 <code>false</code>인 경우,
1046두 번째 인수로 전달된 기본 값을 사용해야 합니다.</p>
1047
1048<pre>
1049&#64;Override
1050protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
1051    if (restorePersistedValue) {
1052        // Restore existing state
1053        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
1054    } else {
1055        // Set default state from the XML attribute
1056        mCurrentValue = (Integer) defaultValue;
1057        persistInt(mCurrentValue);
1058    }
1059}
1060</pre>
1061
1062<p>각 {@code getPersisted*()} 메서드는 기본 값을 나타내는 인수를 취하여
1063사실은 유지된 값이 전혀 없거나 키 자체가 존재하지 않는 경우 사용하도록 합니다. 위의
1064예시에서는 혹시 {@link
1065android.preference.Preference#getPersistedInt getPersistedInt()}가 유지된 값을 반환할 수 없는 경우에 사용하도록 기본 값을 나타내는 데 로컬 상수를 사용하였습니다.</p>
1066
1067<p class="caution"><strong>주의:</strong> {@code getPersisted*()} 메서드에서는
1068<code>defaultValue</code>를 기본 값으로 사용하면 <strong>안 됩니다</strong>. 이것의 값은
1069<code>restorePersistedValue</code>가 <code>true</code>이면 항상 null이기 때문입니다.</p>
1070
1071
1072<h3 id="CustomDefault">기본 값 제공하기</h3>
1073
1074<p>{@link android.preference.Preference} 클래스의 인스턴스가 기본 값을 나타내는 경우
1075({@code android:defaultValue} 속성으로), 시스템은
1076값을 검색하기 위해 객체를 인스턴트화할 때 {@link android.preference.Preference#onGetDefaultValue
1077onGetDefaultValue()}를 호출합니다. 이 메서드를 구현해야
1078시스템이 {@link
1079android.content.SharedPreferences}에 있는 기본 값을 저장할 수 있습니다. 예:</p>
1080
1081<pre>
1082&#64;Override
1083protected Object onGetDefaultValue(TypedArray a, int index) {
1084    return a.getInteger(index, DEFAULT_VALUE);
1085}
1086</pre>
1087
1088<p>이 메서드 인수가 여러분에게 필요한 모든 것을 제공합니다. 즉 속성 배열과
1089{@code android:defaultValue}의 위치로, 이는 반드시 검색해야 합니다. 이 메서드를
1090반드시 구현하여 속성에서 기본 값을 추출해야만 하는 이유는 값이 정의되지 않은 경우, 속성에 대한
1091로컬 기본 값을 꼭 지정해야 하기 때문입니다.</p>
1092
1093
1094
1095<h3 id="CustomSaveState">기본 설정의 상태 저장 및 복원하기</h3>
1096
1097<p>레이아웃에서의 {@link android.view.View}와 마찬가지로 {@link android.preference.Preference}
1098하위 클래스가 액티비티 또는 프래그먼트가 재시작했을 때
1099그 상태를 저장하고 복원하는 역할을 맡습니다(예를 들어 사용자가 화면을 돌리는 경우 등).
1100{@link android.preference.Preference} 클래스의 상태를 적절하게 저장하고 복원하려면,
1101수명 주기 콜백 메서드 {@link android.preference.Preference#onSaveInstanceState
1102onSaveInstanceState()} 및 {@link
1103android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}를 구현해야 합니다.</p>
1104
1105<p>{@link android.preference.Preference}의 상태를 정의하는 것은
1106{@link android.os.Parcelable} 인터페이스를 구현하는 객체입니다. Android 프레임워크는
1107그러한 객체를 제공하여 상태 객체를 정의하는 데 일종의 시작 지점으로 사용하도록 하고 있습니다. 즉 {@link
1108android.preference.Preference.BaseSavedState} 클래스가 이에 해당됩니다.</p>
1109
1110<p>{@link android.preference.Preference} 클래스가 자신의 상태를 저장하는 방법을 정의하려면
1111{@link android.preference.Preference.BaseSavedState} 클래스를 확장해야 합니다. 아주 약간의 메서드를 재정의하고
1112{@link android.preference.Preference.BaseSavedState#CREATOR}
1113객체를 정의해야 합니다.</p>
1114
1115<p>대부분의 앱에서는 다음과 같은 구현을 복사한 다음,
1116{@code value}를 처리하는 줄만 변경하면 됩니다. 이는 {@link android.preference.Preference} 하위 클래스가 정수보다는 데이터
1117유형을 저장하는 경우 해당됩니다.</p>
1118
1119<pre>
1120private static class SavedState extends BaseSavedState {
1121    // Member that holds the setting's value
1122    // Change this data type to match the type saved by your Preference
1123    int value;
1124
1125    public SavedState(Parcelable superState) {
1126        super(superState);
1127    }
1128
1129    public SavedState(Parcel source) {
1130        super(source);
1131        // Get the current preference's value
1132        value = source.readInt();  // Change this to read the appropriate data type
1133    }
1134
1135    &#64;Override
1136    public void writeToParcel(Parcel dest, int flags) {
1137        super.writeToParcel(dest, flags);
1138        // Write the preference's value
1139        dest.writeInt(value);  // Change this to write the appropriate data type
1140    }
1141
1142    // Standard creator object using an instance of this class
1143    public static final Parcelable.Creator&lt;SavedState> CREATOR =
1144            new Parcelable.Creator&lt;SavedState>() {
1145
1146        public SavedState createFromParcel(Parcel in) {
1147            return new SavedState(in);
1148        }
1149
1150        public SavedState[] newArray(int size) {
1151            return new SavedState[size];
1152        }
1153    };
1154}
1155</pre>
1156
1157<p>위의 {@link android.preference.Preference.BaseSavedState} 구현을 앱에
1158추가하고 나면(주로 {@link android.preference.Preference} 하위 클래스의 하위 클래스로), 이제
1159{@link android.preference.Preference#onSaveInstanceState
1160onSaveInstanceState()} 및 {@link
1161android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} 메서드를 구현해야 합니다. 이것은
1162{@link android.preference.Preference} 하위 클래스를 위한 것입니다.</p>
1163
1164<p>예:</p>
1165
1166<pre>
1167&#64;Override
1168protected Parcelable onSaveInstanceState() {
1169    final Parcelable superState = super.onSaveInstanceState();
1170    // Check whether this Preference is persistent (continually saved)
1171    if (isPersistent()) {
1172        // No need to save instance state since it's persistent,
1173        // use superclass state
1174        return superState;
1175    }
1176
1177    // Create instance of custom BaseSavedState
1178    final SavedState myState = new SavedState(superState);
1179    // Set the state's value with the class member that holds current
1180    // setting value
1181    myState.value = mNewValue;
1182    return myState;
1183}
1184
1185&#64;Override
1186protected void onRestoreInstanceState(Parcelable state) {
1187    // Check whether we saved the state in onSaveInstanceState
1188    if (state == null || !state.getClass().equals(SavedState.class)) {
1189        // Didn't save the state, so call superclass
1190        super.onRestoreInstanceState(state);
1191        return;
1192    }
1193
1194    // Cast state to custom BaseSavedState and pass to superclass
1195    SavedState myState = (SavedState) state;
1196    super.onRestoreInstanceState(myState.getSuperState());
1197
1198    // Set this Preference's widget to reflect the restored state
1199    mNumberPicker.setValue(myState.value);
1200}
1201</pre>
1202
1203