1page.title=Thiết đặt 2page.tags=preference,preferenceactivity,preferencefragment 3 4@jd:body 5 6 7<div id="qv-wrapper"> 8<div id="qv"> 9 10<h2>Trong tài liệu này</h2> 11<ol> 12 <li><a href="#Overview">Tổng quan</a> 13 <ol> 14 <li><a href="#SettingTypes">Tùy chọn</a></li> 15 </ol> 16 </li> 17 <li><a href="#DefiningPrefs">Định nghĩa Tùy chọn trong XML</a> 18 <ol> 19 <li><a href="#Groups">Tạo nhóm thiết đặt</a></li> 20 <li><a href="#Intents">Sử dụng ý định</a></li> 21 </ol> 22 </li> 23 <li><a href="#Activity">Tạo một Hoạt động Tùy chọn</a></li> 24 <li><a href="#Fragment">Sử dụng Phân đoạn Tùy chọn</a></li> 25 <li><a href="#Defaults">Thiết đặt Giá trị Mặc định</a></li> 26 <li><a href="#PreferenceHeaders">Sử dụng Tiêu đề Tùy chọn</a> 27 <ol> 28 <li><a href="#CreateHeaders">Tạo tệp tiêu đề</a></li> 29 <li><a href="#DisplayHeaders">Hiển thị tiêu đề</a></li> 30 <li><a href="#BackCompatHeaders">Hỗ trợ các phiên bản cũ hơn với tiêu đề tùy chọn</a></li> 31 </ol> 32 </li> 33 <li><a href="#ReadingPrefs">Đọc Tùy chọn</a> 34 <ol> 35 <li><a href="#Listening">Theo dõi thay đổi tùy chọn</a></li> 36 </ol> 37 </li> 38 <li><a href="#NetworkUsage">Quản lý Sử dụng Mạng</a></li> 39 <li><a href="#Custom">Xây dựng một Thiết đặt Tùy chỉnh</a> 40 <ol> 41 <li><a href="#CustomSelected">Quy định một giao diện người dùng</a></li> 42 <li><a href="#CustomSave">Lưu giá trị của thiết đặt</a></li> 43 <li><a href="#CustomInitialize">Khởi tạo giá trị hiện tại</a></li> 44 <li><a href="#CustomDefault">Cung cấp một giá trị mặc định</a></li> 45 <li><a href="#CustomSaveState">Lưu và khôi phục trạng thái của Tùy chọn</a></li> 46 </ol> 47 </li> 48</ol> 49 50<h2>Lớp khóa</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>Xem thêm</h2> 59<ol> 60 <li><a href="{@docRoot}design/patterns/settings.html">Hướng dẫn thiết kế Thiết đặt</a></li> 61</ol> 62</div> 63</div> 64 65 66 67 68<p>Ứng dụng thường bao gồm những thiết đặt cho phép người dùng sửa đổi các tính năng và hành vi của ứng dụng. Ví 69dụ, một số ứng dụng cho phép người dùng quy định xem thông báo có được kích hoạt hay không hoặc quy định tần suất 70ứng dụng sẽ đồng bộ dữ liệu với đám mây.</p> 71 72<p>Nếu muốn cung cấp thiết đặt cho ứng dụng của mình, bạn nên sử dụng 73các API {@link android.preference.Preference} của Android để xây dựng một giao diện phù hợp với 74trải nghiệm người dùng trong các ứng dụng Android khác (bao gồm thiết đặt hệ thống). Tài liệu này mô tả 75cách xây dựng thiết đặt ứng dụng của bạn bằng cách sử dụng các API {@link android.preference.Preference}.</p> 76 77<div class="note design"> 78<p><strong>Thiết kế Thiết đặt</strong></p> 79 <p>Để biết thông tin về cách thiết kế thiết đặt của bạn, hãy đọc hướng dẫn thiết kế <a href="{@docRoot}design/patterns/settings.html">Thiết đặt</a>.</p> 80</div> 81 82 83<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" /> 84<p class="img-caption"><strong>Hình 1.</strong> Ảnh chụp màn hình từ thiết đặt của ứng dụng 85Messaging trên Android. Chọn một mục được định nghĩa bởi một {@link android.preference.Preference} 86sẽ mở ra một giao diện để thay đổi thiết đặt.</p> 87 88 89 90 91<h2 id="Overview">Tổng quan</h2> 92 93<p>Thay vì sử dụng các đối tượng {@link android.view.View} để xây dựng giao diện người dùng, thiết đặt được 94xây dựng bằng cách sử dụng các lớp con khác nhau của lớp {@link android.preference.Preference} mà bạn 95khai báo trong một tệp XML.</p> 96 97<p>Đối tượng {@link android.preference.Preference} là một khối dựng cho một thiết đặt 98đơn lẻ. Mỗi {@link android.preference.Preference} xuất hiện như một mục trong một danh sách và cung cấp 99UI phù hợp để người dùng sửa đổi thiết đặt. Ví dụ, một {@link 100android.preference.CheckBoxPreference} tạo một mục danh sách hiển thị một hộp kiểm, và một {@link 101android.preference.ListPreference} tạo một mục mở ra một hộp thoại với danh sách lựa chọn.</p> 102 103<p>Mỗi {@link android.preference.Preference} mà bạn thêm có một cặp khóa-giá trị tương ứng mà 104hệ thống sử dụng để lưu thiết đặt trong một tệp {@link android.content.SharedPreferences} 105mặc định cho thiết đặt của ứng dụng của bạn. Khi người dùng thay đổi một thiết đặt, hệ thống sẽ cập nhật giá trị 106tương ứng trong tệp {@link android.content.SharedPreferences} cho bạn. Lần duy nhất mà bạn nên 107trực tiếp tương tác với tệp {@link android.content.SharedPreferences} được liên kết đó là khi bạn 108cần đọc giá trị để xác định xem hành vi ứng dụng của mình có được dựa trên thiết đặt của người dùng không.</p> 109 110<p>Giá trị được lưu trong {@link android.content.SharedPreferences} cho từng thiết đặt có thể là một trong các kiểu dữ liệu 111sau:</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>Vì thiết đặt của ứng dụng của bạn được xây dựng bằng cách sử dụng các đối tượng {@link android.preference.Preference} 123thay vì đối tượng 124{@link android.view.View}, bạn nên sử dụng một lớp con {@link android.app.Activity} hoặc 125{@link android.app.Fragment} chuyên dụng để hiển thị thiết đặt danh sách:</p> 126 127<ul> 128 <li>Nếu ứng dụng của bạn hỗ trợ các phiên bản Android cũ hơn 3.0 (API mức 10 và thấp hơn), bạn phải 129xây dựng hoạt động như một phần mở rộng của lớp {@link android.preference.PreferenceActivity}.</li> 130 <li>Trên phiên bản Android 3.0 trở lên, thay vào đó, bạn nên sử dụng một {@link android.app.Activity} 131truyền thống nơi lưu giữ {@link android.preference.PreferenceFragment} để hiển thị thiết đặt ứng dụng của bạn. 132Tuy nhiên, bạn cũng có thể sử dụng {@link android.preference.PreferenceActivity} để tạo một bố trí hai bảng 133cho màn hình lớn khi bạn có nhiều nhóm thiết đặt.</li> 134</ul> 135 136<p>Cách thiết đặt {@link android.preference.PreferenceActivity} của bạn và các thực thể của {@link 137android.preference.PreferenceFragment} được trình bày trong các phần về <a href="#Activity">Tạo một Hoạt động Tùy chọn</a> và <a href="#Fragment">Sử dụng 138Phân đoạn Tùy chọn</a>.</p> 139 140 141<h3 id="SettingTypes">Tùy chọn</h3> 142 143<p>Mọi thiết đặt cho ứng dụng của bạn đều được biểu diễn bởi một lớp con cụ thể của lớp {@link 144android.preference.Preference}. Mỗi lớp con lại bao gồm một tập hợp các tính chất cốt lõi cho phép bạn 145quy định những thứ như tiêu đề cho thiết đặt và giá trị mặc định. Mỗi lớp con cũng cung cấp 146các tính chất và giao diện người dùng chuyên dụng của chính nó. Ví dụ, hình 1 mình họa một ảnh chụp màn hình từ thiết đặt của ứng dụng 147Messaging. Mỗi mục danh sách trong màn hình thiết đặt được hỗ trợ bởi một đối tượng {@link 148android.preference.Preference} khác nhau.</p> 149 150<p>Sau đây là một số tùy chọn phổ biến nhất:</p> 151 152<dl> 153 <dt>{@link android.preference.CheckBoxPreference}</dt> 154 <dd>Hiển thị một mục kèm một hộp kiểm cho thiết đặt hoặc được kích hoạt hoặc bị vô hiệu hóa. Giá trị 155được lưu là một boolean (<code>true</code> nếu nó được chọn).</dd> 156 157 <dt>{@link android.preference.ListPreference}</dt> 158 <dd>Mở một hộp thoại kèm danh sách nút chọn một. Giá trị được lưu 159có thể là bất kỳ loại giá trị được hỗ trợ nào (liệt kê bên trên).</dd> 160 161 <dt>{@link android.preference.EditTextPreference}</dt> 162 <dd>Mở một hộp thoại kèm một widget {@link android.widget.EditText}. Giá trị được lưu là một {@link 163java.lang.String}.</dd> 164</dl> 165 166<p>Xem lớp {@link android.preference.Preference} để biết danh sách tất cả các lớp con khác và tính chất 167tương ứng của chúng.</p> 168 169<p>Dĩ nhiên, các lớp tích hợp không đáp ứng mọi nhu cầu và ứng dụng của bạn có thể yêu cầu 170lớp con chuyên dụng hơn. Ví dụ, nền tảng này hiện chưa cung cấp một lớp {@link 171android.preference.Preference} cho việc chọn một số hay ngày. Vì thế, bạn có thể cần phải định nghĩa 172lớp con {@link android.preference.Preference} của chính mình. Để được trợ giúp khi làm vậy, hãy xem phần về <a href="#Custom">Xây dựng Thiết đặt Tùy chỉnh</a>.</p> 173 174 175 176<h2 id="DefiningPrefs">Định nghĩa Tùy chọn trong XML</h2> 177 178<p>Mặc dù bạn có thể khởi tạo các đối tượng {@link android.preference.Preference} mới vào thời gian chạy, bạn 179nên định nghĩa danh sách các thiết đặt của mình trong XML kèm một phân cấp của các đối tượng {@link android.preference.Preference} 180. Việc sử dụng một tệp XML để định nghĩa bộ sưu tập thiết đặt của bạn sẽ được ưu tiên vì tệp 181cung cấp một cấu trúc dễ đọc, cập nhật đơn giản. Bên cạnh đó, các thiết đặt ứng dụng của bạn thường được 182xác định trước, mặc dù bạn vẫn có thể sửa đổi bộ sưu tập vào thời gian chạy.</p> 183 184<p>Mỗi lớp con {@link android.preference.Preference} có thể được khai báo bằng một phần tử XML mà 185khớp với tên lớp đó, chẳng hạn như {@code <CheckBoxPreference>}.</p> 186 187<p>Bạn phải lưu tệp XML trong thư mục {@code res/xml/}. Mặc dù bạn có thể đặt tên tệp là 188bất cứ thứ gì mình muốn, nó thường được đặt tên là{@code preferences.xml}. Bạn thường chỉ cần một tệp, 189bởi các nhánh trong phân cấp (mà mở danh sách thiết đặt của riêng chúng) sẽ được khai báo bằng cách sử dụng các thực thể 190lồng nhau của {@link android.preference.PreferenceScreen}.</p> 191 192<p class="note"><strong>Lưu ý:</strong> Nếu bạn muốn tạo một bố trí đa bảng cho thiết đặt 193của mình, vậy bạn nên tách riêng các tệp XML cho từng phân đoạn.</p> 194 195<p>Node gốc cho tệp XML phải là một phần tử {@link android.preference.PreferenceScreen 196<PreferenceScreen>}. Trong phần tử này là nơi bạn thêm từng {@link 197android.preference.Preference}. Từng phần tử con mà bạn thêm vào trong phần tử 198{@link android.preference.PreferenceScreen <PreferenceScreen>} sẽ xuất hiện như một mục 199đơn lẻ trong danh sách thiết đặt.</p> 200 201<p>Ví dụ:</p> 202 203<pre> 204<?xml version="1.0" encoding="utf-8"?> 205<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 206 <CheckBoxPreference 207 android:key="pref_sync" 208 android:title="@string/pref_sync" 209 android:summary="@string/pref_sync_summ" 210 android:defaultValue="true" /> 211 <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</PreferenceScreen> 220</pre> 221 222<p>Trong ví dụ này, có một {@link android.preference.CheckBoxPreference} và một {@link 223android.preference.ListPreference}. Cả hai mục đều bao gồm ba thuộc tính sau:</p> 224 225<dl> 226 <dt>{@code android:key}</dt> 227 <dd>Thuộc tính này được yêu cầu cho các tùy chọn duy trì một giá trị dữ liệu. Nó quy định khóa 228(xâu) duy nhất mà hệ thống sử dụng khi lưu giá trị của thiết đặt này trong {@link 229android.content.SharedPreferences}. 230 <p>Các thực thể duy nhất mà thuộc tính này không <em>được yêu cầu</em> là khi tùy chọn là một 231{@link android.preference.PreferenceCategory} hoặc {@link android.preference.PreferenceScreen}, hoặc 232tùy chọn quy định một {@link android.content.Intent} để gọi ra (bằng phần tử <a href="#Intents">{@code <intent>}</a>) hoặc {@link android.app.Fragment} để hiển thị (bằng thuộc tính <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>Thuộc tính này cung cấp một tên hiển thị với người dùng cho thiết đặt.</dd> 237 <dt>{@code android:defaultValue}</dt> 238 <dd>Nó quy định giá trị ban đầu mà hệ thống nên đặt trong tệp {@link 239android.content.SharedPreferences}. Bạn nên cung cấp một giá trị mặc định cho tất cả 240thiết đặt.</dd> 241</dl> 242 243<p>Để biết thông tin về tất cả thuộc tính được hỗ trợ khác, hãy xem tài liệu {@link 244android.preference.Preference} (và lớp con tương ứng).</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>Hình 2.</strong> Thiết đặt thể loại 250 có tiêu đề. <br/><b>1.</b> Thể loại được quy định bởi phần tử {@link 251android.preference.PreferenceCategory <PreferenceCategory>}. <br/><b>2.</b> Tiêu đề 252được quy định bằng thuộc tính {@code android:title}.</p> 253</div> 254 255 256<p>Khi danh sách thiết đặt của bạn vượt quá khoảng 10 mục, bạn có thể muốn thêm tiêu đề để 257định nghĩa các nhóm thiết đặt hoặc hiển thị các nhóm đó trong một 258màn hình riêng. Những tùy chọn này được mô tả trong các phần sau.</p> 259 260 261<h3 id="Groups">Tạo nhóm thiết đặt</h3> 262 263<p>Nếu bạn trình bày một danh sách từ 10 thiết đặt trở lên, người dùng 264có thể gặp khó khăn trong việc dò tìm, hiểu và xử lý chúng. Bạn có thể khắc phục điều này bằng cách 265chia một số hoặc tất cả thiết đặt thành các nhóm, qua đó biến một danh sách dài thành nhiều 266danh sách ngắn hơn. Một nhóm các thiết đặt có liên quan có thể được trình bày bằng một trong hai cách:</p> 267 268<ul> 269 <li><a href="#Titles">Sử dụng tiêu đề</a></li> 270 <li><a href="#Subscreens">Sử dụng màn hình con</a></li> 271</ul> 272 273<p>Bạn có thể sử dụng một hoặc cả hai kỹ thuật tạo nhóm này để sắp xếp các thiết đặt cho ứng dụng của mình. Khi 274quyết định sử dụng cái nào và làm thế nào để chia các thiết đặt của mình, bạn nên tuân theo các hướng dẫn trong tài liệu hướng dẫn 275<a href="{@docRoot}design/patterns/settings.html">Thiết đặt</a> của Thiết kế Android.</p> 276 277 278<h4 id="Titles">Sử dụng tiêu đề</h4> 279 280<p>Nếu bạn muốn cung cấp các thanh chia có tiêu đề giữa các nhóm thiết đặt (như minh họa trong hình 2), 281hãy đặt từng nhóm đối tượng {@link android.preference.Preference} vào bên trong một {@link 282android.preference.PreferenceCategory}.</p> 283 284<p>Ví dụ:</p> 285 286<pre> 287<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 288 <PreferenceCategory 289 android:title="@string/pref_sms_storage_title" 290 android:key="pref_key_storage_settings"> 291 <CheckBoxPreference 292 android:key="pref_key_auto_delete" 293 android:summary="@string/pref_summary_auto_delete" 294 android:title="@string/pref_title_auto_delete" 295 android:defaultValue="false"... /> 296 <Preference 297 android:key="pref_key_sms_delete_limit" 298 android:dependency="pref_key_auto_delete" 299 android:summary="@string/pref_summary_delete_limit" 300 android:title="@string/pref_title_sms_delete"... /> 301 <Preference 302 android:key="pref_key_mms_delete_limit" 303 android:dependency="pref_key_auto_delete" 304 android:summary="@string/pref_summary_delete_limit" 305 android:title="@string/pref_title_mms_delete" ... /> 306 </PreferenceCategory> 307 ... 308</PreferenceScreen> 309</pre> 310 311 312<h4 id="Subscreens">Sử dụng màn hình con</h4> 313 314<p>Nếu bạn muốn đặt các nhóm thiết đặt vào một màn hình con (như minh họa trong hình 3), hãy đặt nhóm 315các đối tượng {@link android.preference.Preference} vào bên trong một {@link 316android.preference.PreferenceScreen}.</p> 317 318<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" /> 319<p class="img-caption"><strong>Hình 3.</strong> Màn hình con thiết đặt. Phần tử {@code 320<PreferenceScreen>} sẽ tạo 321một mục mà, khi được chọn, nó sẽ mở ra một danh sách riêng để hiển thị các thiết đặt lồng nhau.</p> 322 323<p>Ví dụ:</p> 324 325<pre> 326<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 327 <!-- opens a subscreen of settings --> 328 <PreferenceScreen 329 android:key="button_voicemail_category_key" 330 android:title="@string/voicemail" 331 android:persistent="false"> 332 <ListPreference 333 android:key="button_voicemail_provider_key" 334 android:title="@string/voicemail_provider" ... /> 335 <!-- opens another nested subscreen --> 336 <PreferenceScreen 337 android:key="button_voicemail_setting_key" 338 android:title="@string/voicemail_settings" 339 android:persistent="false"> 340 ... 341 </PreferenceScreen> 342 <RingtonePreference 343 android:key="button_voicemail_ringtone_key" 344 android:title="@string/voicemail_ringtone_title" 345 android:ringtoneType="notification" ... /> 346 ... 347 </PreferenceScreen> 348 ... 349</PreferenceScreen> 350</pre> 351 352 353<h3 id="Intents">Sử dụng ý định</h3> 354 355<p>Trong một số trường hợp, bạn có thể muốn một mục tùy chọn mở một hoạt động khác thay vì một 356màn hình thiết đặt, chẳng hạn như một trình duyệt web để xem một trang web. Để gọi ra một {@link 357android.content.Intent} khi người dùng chọn một mục tùy chọn, hãy thêm một phần tử {@code <intent>} 358làm con của phần tử {@code <Preference>} tương ứng.</p> 359 360<p>Ví dụ, sau đây là cách bạn có thể sử dụng một mục tùy chọn để mở một trang web:</p> 361 362<pre> 363<Preference android:title="@string/prefs_web_page" > 364 <intent android:action="android.intent.action.VIEW" 365 android:data="http://www.example.com" /> 366</Preference> 367</pre> 368 369<p>Bạn có thể tạo cả ý định biểu thị và không biểu thị bằng cách sử dụng các thuộc tính sau:</p> 370 371<dl> 372 <dt>{@code android:action}</dt> 373 <dd>Hành động cần gán, theo mỗi phương pháp {@link android.content.Intent#setAction setAction()} 374.</dd> 375 <dt>{@code android:data}</dt> 376 <dd>Dữ liệu cần gán, theo mỗi phương pháp {@link android.content.Intent#setData setData()}.</dd> 377 <dt>{@code android:mimeType}</dt> 378 <dd>Kiểu MIME cần gán, theo mỗi phương pháp {@link android.content.Intent#setType setType()} 379.</dd> 380 <dt>{@code android:targetClass}</dt> 381 <dd>Phần lớp của tên thành phần, theo mỗi phương pháp {@link android.content.Intent#setComponent 382setComponent()}.</dd> 383 <dt>{@code android:targetPackage}</dt> 384 <dd>Phần gói của tên thành phần, theo mỗi phương pháp {@link 385android.content.Intent#setComponent setComponent()}.</dd> 386</dl> 387 388 389 390<h2 id="Activity">Tạo một Hoạt động Tùy chọn</h2> 391 392<p>Để hiển thị thiết đặt của bạn trong một hoạt động, hãy mở rộng lớp {@link 393android.preference.PreferenceActivity}. Đây là phần mở rộng của lớp {@link 394android.app.Activity} truyền thống mà hiển thị một danh sách các thiết đặt dựa trên một phân cấp của các đối tượng {@link 395android.preference.Preference}. {@link android.preference.PreferenceActivity} 396sẽ tự động duy trì các thiết đặt liên kết với từng {@link 397android.preference.Preference} khi người dùng thực hiện một thay đổi.</p> 398 399<p class="note"><strong>Lưu ý:</strong> Nếu bạn đang phát triển ứng dụng của mình cho phiên bản Android 3.0 và 400cao hơn, thay vào đó bạn nên sử dụng {@link android.preference.PreferenceFragment}. Đi đến phần 401tiếp theo về <a href="#Fragment">Sử dụng Phân đoạn Tùy chọn</a>.</p> 402 403<p>Điều quan trọng nhất cần nhớ đó là bạn không được tải một bố trí dạng xem trong khi gọi lại {@link 404android.preference.PreferenceActivity#onCreate onCreate()}. Thay vào đó, bạn hãy gọi {@link 405android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} để 406thêm tùy chọn mà bạn đã khai báo trong một tệp XML vào hoạt động. Ví dụ, sau đây là đoạn mã tối thiểu 407cần thiết cho một {@link android.preference.PreferenceActivity} chức năng:</p> 408 409<pre> 410public class SettingsActivity extends PreferenceActivity { 411 @Override 412 public void onCreate(Bundle savedInstanceState) { 413 super.onCreate(savedInstanceState); 414 addPreferencesFromResource(R.xml.preferences); 415 } 416} 417</pre> 418 419<p>Đây là đoạn mã vừa đủ cho một số ứng dụng bởi ngay khi người dùng sửa đổi một tùy chọn, 420hệ thống sẽ lưu thay đổi đối với tệp {@link android.content.SharedPreferences} mặc định mà các 421thành phần ứng dụng khác của bạn có thể đọc khi bạn cần kiểm tra thiết đặt của người dùng. Tuy nhiên, 422nhiều ứng dụng lại yêu cầu thêm mã để theo dõi những thay đổi xảy ra với các tùy chọn đó. 423Để biết thông tin về việc theo dõi thay đổi trong tệp {@link android.content.SharedPreferences}, 424hãy xem phần về <a href="#ReadingPrefs">Đọc Tùy chọn</a>.</p> 425 426 427 428 429<h2 id="Fragment">Sử dụng Phân đoạn Tùy chọn</h2> 430 431<p>Nếu bạn đang phát triển cho phiên bản Android 3.0 (API mức 11) trở lên, bạn nên sử dụng một {@link 432android.preference.PreferenceFragment} để hiển thị danh sách các đối tượng {@link android.preference.Preference} 433của bạn. Bạn có thể thêm một {@link android.preference.PreferenceFragment} vào bất kỳ hoạt động nào—bạn không cần 434sử dụng {@link android.preference.PreferenceActivity}.</p> 435 436<p><a href="{@docRoot}guide/components/fragments.html">Phân đoạn</a> cung cấp một kiến trúc 437linh hoạt hơn cho ứng dụng của bạn, so với việc sử dụng chỉ các hoạt động, dù loại hoạt động 438mà bạn đang xây dựng là gì. Như vậy, chúng tôi gợi ý bạn sử dụng {@link 439android.preference.PreferenceFragment} để kiểm soát hiển thị các thiết đặt của mình thay cho {@link 440android.preference.PreferenceActivity} khi có thể.</p> 441 442<p>Việc triển khai {@link android.preference.PreferenceFragment} có thể chỉ đơn giản như 443định nghĩa phương pháp {@link android.preference.PreferenceFragment#onCreate onCreate()} để tải một 444tệp tùy chọn bằng {@link android.preference.PreferenceFragment#addPreferencesFromResource 445addPreferencesFromResource()}. Ví dụ:</p> 446 447<pre> 448public static class SettingsFragment extends PreferenceFragment { 449 @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>Khi đó, bạn có thể thêm phân đoạn này vào một {@link android.app.Activity} giống như cách mà bạn sẽ làm với bất kỳ 461{@link android.app.Fragment} nào khác. Ví dụ:</p> 462 463<pre> 464public class SettingsActivity extends Activity { 465 @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>Lưu ý:</strong> {@link android.preference.PreferenceFragment} không có một 478đối tượng {@link android.content.Context} của chính nó. Nếu bạn cần một đối tượng {@link android.content.Context} 479, bạn có thể gọi {@link android.app.Fragment#getActivity()}. Tuy nhiên, hãy chắc chắn là chỉ gọi 480{@link android.app.Fragment#getActivity()} khi phân đoạn đó được gắn kèm với một hoạt động. Khi 481phân đoạn chưa được gắn kèm, hoặc bị bỏ gắn kèm trong khi kết thúc vòng đời của nó, {@link 482android.app.Fragment#getActivity()} sẽ trả về rỗng.</p> 483 484 485<h2 id="Defaults">Thiết đặt Giá trị Mặc định</h2> 486 487<p>Tùy chọn mà bạn tạo có thể định nghĩa một số hành vi quan trọng cho ứng dụng của bạn, vì thế 488bạn cần phải khởi tạo tệp {@link android.content.SharedPreferences} kèm theo với các 489giá trị mặc định cho từng {@link android.preference.Preference} khi người dùng lần đầu mở 490ứng dụng của bạn.</p> 491 492<p>Điều đầu tiên bạn phải làm đó là quy định một giá trị mặc định cho từng đối tượng {@link 493android.preference.Preference} 494trong tệp XML của bạn bằng cách sử dụng thuộc tính {@code android:defaultValue}. Giá trị đó có thể là bất kỳ kiểu 495dữ liệu nào mà phù hợp với đối tượng {@link android.preference.Preference} tương ứng. Ví 496dụ:</p> 497 498<pre> 499<!-- default value is a boolean --> 500<CheckBoxPreference 501 android:defaultValue="true" 502 ... /> 503 504<!-- default value is a string --> 505<ListPreference 506 android:defaultValue="@string/pref_syncConnectionTypes_default" 507 ... /> 508</pre> 509 510<p>Khi đó, từ phương pháp {@link android.app.Activity#onCreate onCreate()} trong hoạt động chính 511—của ứng dụng của bạn và trong bất kỳ hoạt động nào khác mà thông qua đó người dùng có thể vào ứng dụng của bạn lần 512đầu tiên—hãy gọi {@link android.preference.PreferenceManager#setDefaultValues 513setDefaultValues()}:</p> 514 515<pre> 516PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false); 517</pre> 518 519<p>Việc gọi này trong khi {@link android.app.Activity#onCreate onCreate()} sẽ đảm bảo rằng 520ứng dụng của bạn được khởi tạo phù hợp với các thiết đặt mặc định mà ứng dụng của bạn có thể cần 521đọc để xác định một số hành vi (chẳng hạn như có tải xuống dữ liệu trong khi đang trên 522mạng di động hay không).</p> 523 524<p>Phương pháp này dùng ba tham đối:</p> 525<ul> 526 <li>{@link android.content.Context} ứng dụng của bạn.</li> 527 <li>ID tài nguyên cho tệp XML tùy chọn mà bạn muốn đặt các giá trị mặc định cho.</li> 528 <li>Một boolean cho biết các giá trị mặc định có nên được đặt nhiều hơn một lần hay không. 529<p>Khi tham đối này là <code>false</code>, hệ thống sẽ đặt các giá trị mặc định chỉ khi phương pháp này chưa từng được 530gọi trước đây (hoặc {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} 531trong tệp tùy chọn được chia sẻ giá trị mặc định là sai).</p></li> 532</ul> 533 534<p>Miễn là bạn đặt tham đối thứ ba này thành <code>false</code>, bạn có thể gọi phương pháp này một cách an toàn 535mỗi khi hoạt động của bạn bắt đầu mà không khống chế các tùy chọn đã lưu của người dùng bằng cách đặt lại chúng thành 536mặc định. Tuy nhiên, nếu bạn đặt nó thành <code>true</code>, bạn sẽ khống chế mọi giá trị 537trước đó bằng các giá trị mặc định.</p> 538 539 540 541<h2 id="PreferenceHeaders">Sử dụng Tiêu đề Tùy chọn</h2> 542 543<p>Trong vài trường hợp hiếm gặp, bạn có thể muốn thiết kế các thiết đặt của mình sao cho màn hình thứ nhất 544chỉ hiển thị một danh sách <a href="#Subscreens">các màn hình con</a> (chẳng hạn như trong ứng dụng Thiết đặt của hệ thống, 545như minh họa trong các hình 4 và 5). Khi phát triển thiết kế như vậy cho phiên bản Android 3.0 trở lên, bạn 546nên sử dụng tính năng "tiêu đề" mới trong Android 3.0, thay vì xây dựng màn hình con với các phần tử 547{@link android.preference.PreferenceScreen} lồng nhau.</p> 548 549<p>Để xây dựng thiết đặt có tiêu đề của mình, bạn cần:</p> 550<ol> 551 <li>Tách riêng từng nhóm thiết đặt thành các thực thể riêng của {@link 552android.preference.PreferenceFragment}. Cụ thể, mỗi nhóm thiết đặt cần một tệp XML 553riêng.</li> 554 <li>Tạo một tệp tiêu đề XML liệt kê từng nhóm thiết đặt và khai báo phân đoạn nào 555chứa danh sách thiết đặt tương ứng.</li> 556 <li>Mở rộng lớp {@link android.preference.PreferenceActivity} để lưu trữ các thiết đặt của bạn.</li> 557 <li>Triển khai lệnh gọi lại {@link 558android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} để quy định 559tệp tiêu đề.</li> 560</ol> 561 562<p>Một lợi ích tuyệt vời đối với việc sử dụng thiết kế này đó là {@link android.preference.PreferenceActivity} 563tự động trình bày bố trí hai bảng như minh họa trong hình 4 khi chạy trên màn hình lớn.</p> 564 565<p>Ngay cả khi ứng dụng của bạn hỗ trợ các phiên bản Android cũ hơn 3.0, bạn có thể xây dựng ứng dụng 566của mình để sử dụng {@link android.preference.PreferenceFragment} cho một trình chiếu hai bảng trên 567các thiết bị mới hơn, trong khi vẫn hỗ trợ phân cấp đa màn hình truyền thống trên các thiết bị 568cũ hơn (xem phần nói về <a href="#BackCompatHeaders">Hỗ trợ các phiên bản cũ hơn 569với tiêu đề tùy chọn</a>).</p> 570 571<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" /> 572<p class="img-caption"><strong>Hình 4.</strong> Bố trí có hai bảng với tiêu đề. <br/><b>1.</b> 573Tiêu đề được định nghĩa trong một tệp tiêu đề XML. <br/><b>2.</b> Mỗi nhóm thiết đặt được định nghĩa bởi một 574{@link android.preference.PreferenceFragment}, được quy định bởi một phần tử {@code <header>} trong tệp tiêu đề 575.</p> 576 577<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" /> 578<p class="img-caption"><strong>Hình 5.</strong> Thiết bị cầm tay với các tiêu đề thiết đặt. Khi một 579mục được chọn, {@link android.preference.PreferenceFragment} được liên kết sẽ thay thế 580tiêu đề.</p> 581 582 583<h3 id="CreateHeaders" style="clear:left">Tạo tệp tiêu đề</h3> 584 585<p>Mỗi nhóm thiết đặt trong danh sách tiêu đề của bạn được quy định bởi một phần tử {@code <header>} 586đơn lẻ bên trong một phần tử {@code <preference-headers>} gốc. Ví dụ:</p> 587 588<pre> 589<?xml version="1.0" encoding="utf-8"?> 590<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> 591 <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 <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 <!-- key/value pairs can be included as arguments for the fragment. --> 600 <extra android:name="someKey" android:value="someHeaderValue" /> 601 </header> 602</preference-headers> 603</pre> 604 605<p>Với thuộc tính {@code android:fragment}, mỗi tiêu đề sẽ khai báo một thực thể của {@link 606android.preference.PreferenceFragment} mà sẽ mở khi người dùng chọn tiêu đề đó.</p> 607 608<p>Phần tử {@code <extras>} cho phép bạn chuyển các cặp khóa-giá trị sang phân đoạn trong một {@link 609android.os.Bundle}. Phân đoạn có thể truy xuất các tham đối bằng cách gọi {@link 610android.app.Fragment#getArguments()}. Bạn có thể chuyển các tham đối tới phân đoạn vì nhiều 611lý do khác nhau, nhưng một lý do chính đáng đó là để sử dụng lại cùng lớp con của {@link 612android.preference.PreferenceFragment} cho mỗi nhóm và sử dụng tham đối để quy định 613tệp XML tùy chọn nào mà phân đoạn cần tải.</p> 614 615<p>Ví dụ, sau đây là một phân đoạn mà có thể được tái sử dụng cho nhiều nhóm thiết đặt, khi từng 616tiêu đề định nghĩa một tham đối {@code <extra>} với khóa {@code "settings"}:</p> 617 618<pre> 619public static class SettingsFragment extends PreferenceFragment { 620 @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">Hiển thị tiêu đề</h3> 637 638<p>Để hiển thị tiêu đề tùy chọn, bạn phải triển khai phương pháp gọi lại {@link 639android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} và gọi 640{@link android.preference.PreferenceActivity#loadHeadersFromResource 641loadHeadersFromResource()}. Ví dụ:</p> 642 643<pre> 644public class SettingsActivity extends PreferenceActivity { 645 @Override 646 public void onBuildHeaders(List<Header> target) { 647 loadHeadersFromResource(R.xml.preference_headers, target); 648 } 649} 650</pre> 651 652<p>Khi người dùng chọn một mục từ danh sách tiêu đề, hệ thống sẽ mở {@link 653android.preference.PreferenceFragment} kèm theo.</p> 654 655<p class="note"><strong>Lưu ý:</strong> Khi sử dụng tiêu đề tùy chọn, lớp con {@link 656android.preference.PreferenceActivity} của bạn không cần triển khai phương pháp {@link 657android.preference.PreferenceActivity#onCreate onCreate()}, vì tác vụ cần thiết duy nhất 658cho hoạt động đó là tải tiêu đề.</p> 659 660 661<h3 id="BackCompatHeaders">Hỗ trợ các phiên bản cũ hơn với tiêu đề tùy chọn</h3> 662 663<p>Nếu ứng dụng của bạn hỗ trợ các phiên bản Android cũ hơn 3.0, bạn vẫn có thể sử dụng tiêu đề để 664cung cấp một bố trí hai bảng khi chạy trên Android 3.0 trở lên. Tất cả những việc bạn cần làm đó là tạo một 665tệp XML tùy chọn bổ sung có sử dụng phần tử cơ bản {@link android.preference.Preference 666<Preference>} đóng vai trò như mục tiêu đề (để dùng cho các phiên bản Android 667cũ hơn).</p> 668 669<p>Tuy nhiên, thay vì mở một {@link android.preference.PreferenceScreen} mới, từng phần tử {@link 670android.preference.Preference <Preference>} sẽ gửi một {@link android.content.Intent} tới 671{@link android.preference.PreferenceActivity} mà quy định tệp XML tùy chọn cần 672tải.</p> 673 674<p>Ví dụ, sau đây là một tệp XML cho các tiêu đề tùy chọn được sử dụng trên Android 3.0 675trở lên ({@code res/xml/preference_headers.xml}):</p> 676 677<pre> 678<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> 679 <header 680 android:fragment="com.example.prefs.SettingsFragmentOne" 681 android:title="@string/prefs_category_one" 682 android:summary="@string/prefs_summ_category_one" /> 683 <header 684 android:fragment="com.example.prefs.SettingsFragmentTwo" 685 android:title="@string/prefs_category_two" 686 android:summary="@string/prefs_summ_category_two" /> 687</preference-headers> 688</pre> 689 690<p>Và sau đây là một tệp tùy chọn cung cấp cùng các tiêu đề cho các phiên bản cũ hơn 691Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p> 692 693<pre> 694<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 695 <Preference 696 android:title="@string/prefs_category_one" 697 android:summary="@string/prefs_summ_category_one" > 698 <intent 699 android:targetPackage="com.example.prefs" 700 android:targetClass="com.example.prefs.SettingsActivity" 701 android:action="com.example.prefs.PREFS_ONE" /> 702 </Preference> 703 <Preference 704 android:title="@string/prefs_category_two" 705 android:summary="@string/prefs_summ_category_two" > 706 <intent 707 android:targetPackage="com.example.prefs" 708 android:targetClass="com.example.prefs.SettingsActivity" 709 android:action="com.example.prefs.PREFS_TWO" /> 710 </Preference> 711</PreferenceScreen> 712</pre> 713 714<p>Vì hỗ trợ dành cho {@code <preference-headers>} đã được thêm trong Android 3.0, hệ thống sẽ gọi 715{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} trong {@link 716android.preference.PreferenceActivity} của bạn chỉ khi đang chạy trên phiên bản Androd 3.0 hoặc cao hơn. Để tải 717tệp tiêu đề "kế thừa" ({@code preference_headers_legacy.xml}), bạn phải kiểm tra phiên bản Android 718và, nếu phiên bản cũ hơn Android 3.0 ({@link 719android.os.Build.VERSION_CODES#HONEYCOMB}), hãy gọi {@link 720android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} để 721tải tệp tiêu đề kế thừa. Ví dụ:</p> 722 723<pre> 724@Override 725public void onCreate(Bundle savedInstanceState) { 726 super.onCreate(savedInstanceState); 727 ... 728 729 if (Build.VERSION.SDK_INT < 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@Override 737public void onBuildHeaders(List<Header> target) { 738 loadHeadersFromResource(R.xml.preference_headers, target); 739} 740</pre> 741 742<p>Việc duy nhất còn lại cần làm đó là xử lý {@link android.content.Intent} mà được chuyển vào 743hoạt động để nhận biết tệp tùy chọn nào cần tải. Vì vậy, hãy truy xuất hành động của ý định và so sánh nó với 744các xâu hành động đã biết mà bạn đã sử dụng trong tag {@code <intent>} của XML tùy chọn:</p> 745 746<pre> 747final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE"; 748... 749 750@Override 751public void onCreate(Bundle savedInstanceState) { 752 super.onCreate(savedInstanceState); 753 754 String action = getIntent().getAction(); 755 if (action != null && action.equals(ACTION_PREFS_ONE)) { 756 addPreferencesFromResource(R.xml.preferences); 757 } 758 ... 759 760 else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 761 // Load the legacy preferences headers 762 addPreferencesFromResource(R.xml.preference_headers_legacy); 763 } 764} 765</pre> 766 767<p>Lưu ý rằng các lệnh gọi liên tiếp đến {@link 768android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} sẽ 769xếp chồng tất cả tùy chọn trong một danh sách duy nhất, vì thế hãy chắc chắn rằng nó chỉ được gọi một lần bằng cách liên kết các 770điều kiện với mệnh đề else-if.</p> 771 772 773 774 775 776<h2 id="ReadingPrefs">Đọc Tùy chọn</h2> 777 778<p>Theo mặc định, tất cả tùy chọn của ứng dụng của bạn đều được lưu vào một tệp có thể truy cập từ bất kỳ nơi nào 779trong ứng dụng của bạn bằng cách gọi phương pháp tĩnh {@link 780android.preference.PreferenceManager#getDefaultSharedPreferences 781PreferenceManager.getDefaultSharedPreferences()}. Điều này sẽ trả về đối tượng {@link 782android.content.SharedPreferences} chứa tất cả cặp khóa-giá trị liên kết 783với các đối tượng {@link android.preference.Preference} được sử dụng trong {@link 784android.preference.PreferenceActivity}.</p> 785 786<p>Ví dụ, sau đây là cách bạn có thể đọc một trong các giá trị tùy chọn từ bất kỳ hoạt động nào khác trong ứng dụng 787của mình:</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">Theo dõi thay đổi tùy chọn</h3> 797 798<p>Có một vài lý do khiến bạn có thể muốn được thông báo càng sớm càng tốt nếu người dùng thay đổi một trong các 799tùy chọn. Để nhận một phương pháp gọi lại khi thay đổi xảy ra với bất kỳ tùy chọn nào, 800hãy triển khai giao diện {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener 801SharedPreference.OnSharedPreferenceChangeListener} và đăng ký đối tượng theo dõi cho đối tượng 802{@link android.content.SharedPreferences} bằng cách gọi {@link 803android.content.SharedPreferences#registerOnSharedPreferenceChangeListener 804registerOnSharedPreferenceChangeListener()}.</p> 805 806<p>Giao diện này chỉ có một phương pháp gọi lại, {@link 807android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged 808onSharedPreferenceChanged()}, và bạn có thể thấy đây là cách dễ nhất để triển khai giao diện như một phần 809hoạt động của mình. Ví dụ:</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>Trong ví dụ này, phương pháp sẽ kiểm tra xem thiết đặt bị thay đổi có áp dụng cho một khóa tùy chọn đã biết không. Nó 829sẽ gọi {@link android.preference.PreferenceActivity#findPreference findPreference()} để nhận đối tượng 830{@link android.preference.Preference} đã bị thay đổi để nó có thể sửa đổi tóm tắt 831của mục đó thành mô tả lựa chọn của người dùng. Cụ thể, khi thiết đặt là một {@link 832android.preference.ListPreference} hoặc thiết đặt nhiều lựa chọn khác, bạn nên gọi {@link 833android.preference.Preference#setSummary setSummary()} khi thiết đặt thay đổi để hiển thị 834trạng thái hiện tại (chẳng hạn như thiết đặt Ngủ như minh họa trong hình 5).</p> 835 836<p class="note"><strong>Lưu ý:</strong> Như đã mô tả trong tài liệu Thiết kế Android về <a href="{@docRoot}design/patterns/settings.html">Thiết đặt</a>, chúng tôi khuyên bạn nên cập nhật 837tóm tắt cho {@link android.preference.ListPreference} mỗi khi người dùng thay đổi tùy chọn để 838mô tả thiết đặt hiện tại.</p> 839 840<p>Để quản lý vòng đời trong hoạt động cho phù hợp, chúng tôi khuyên rằng bạn nên đăng ký và bỏ đăng ký 841{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} của mình tương ứng trong {@link 842android.app.Activity#onResume} và các lệnh gọi lại {@link android.app.Activity#onPause}:</p> 843 844<pre> 845@Override 846protected void onResume() { 847 super.onResume(); 848 getPreferenceScreen().getSharedPreferences() 849 .registerOnSharedPreferenceChangeListener(this); 850} 851 852@Override 853protected void onPause() { 854 super.onPause(); 855 getPreferenceScreen().getSharedPreferences() 856 .unregisterOnSharedPreferenceChangeListener(this); 857} 858</pre> 859 860<p class="caution"><strong>Chú ý:</strong> Khi bạn gọi {@link 861android.content.SharedPreferences#registerOnSharedPreferenceChangeListener 862registerOnSharedPreferenceChangeListener()}, trình quản lý tùy chọn hiện 863không lưu trữ một tham chiếu mạnh tới đối tượng theo dõi. Bạn phải lưu trữ một tham chiếu 864mạnh tới đối tượng theo dõi, nếu không nó sẽ dễ bị thu thập thông tin rác. Chúng tôi 865khuyên bạn nên giữ một tham chiếu tới đối tượng theo dõi trong dữ liệu thực thể của một đối tượng 866mà sẽ tồn tại miễn là bạn còn cần đối tượng theo dõi đó.</p> 867 868<p>Ví dụ, trong đoạn mã sau, hàm gọi không giữ tham chiếu tới 869đối tượng theo dõi. Kết quả là đối tượng theo dõi sẽ bị thu thập thông tin rác, 870và nó sẽ bị lỗi tại một thời điểm không xác định trong tương lai:</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>Thay vào đó, hãy lưu một tham chiếu tới đối tượng theo dõi trong một trường dữ liệu thực thể của một 883đối tượng mà sẽ tồn tại miễn là còn cần đối tượng theo dõi đó:</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">Quản lý Sử dụng Mạng</h2> 896 897 898<p>Bắt đầu với Android 4.0, ứng dụng Thiết đặt của hệ thống sẽ cho phép người dùng xem 899ứng dụng của họ đang sử dụng bao nhiêu dữ liệu mạng khi đang ở tiền cảnh và dưới nền. Khi đó, người dùng có thể 900vô hiệu hóa việc sử dụng dữ liệu chạy ngầm cho từng ứng dụng. Để tránh việc người dùng vô hiệu hóa truy cập dữ liệu 901của ứng dụng của bạn từ dưới nền, bạn nên sử dụng kết nối dữ liệu một cách hiệu quả và cho phép 902người dùng tinh chỉnh mức sử dụng dữ liệu cho ứng dụng của bạn thông qua thiết đặt ứng dụng.<p> 903 904<p>Ví dụ, bạn có thể cho phép người dùng kiểm soát tần suất ứng dụng của bạn đồng bộ dữ liệu, ứng dụng của bạn 905chỉ được thực hiện tải lên/tải xuống khi trên Wi-Fi, ứng dụng của bạn sử dụng dữ liệu trong khi đang chuyển vùng dữ liệu, v.v... hay không. Với 906những kiểm soát này, người dùng sẽ ít có khả năng vô hiệu hóa truy cập dữ liệu của ứng dụng của bạn 907hơn nhiều khi họ đạt gần mức giới hạn đặt ra trong Thiết đặt hệ thống, vì thay vào đó, họ có thể kiểm soát chính xác 908lượng dữ liệu mà ứng dụng của bạn sử dụng.</p> 909 910<p>Sau khi bạn đã thêm các tùy chọn cần thiết trong {@link android.preference.PreferenceActivity} 911của mình để kiểm soát các thói quen dữ liệu của ứng dụng của bạn, bạn nên thêm một bộ lọc ý định cho {@link 912android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} trong tệp bản kê khai của mình. Ví dụ:</p> 913 914<pre> 915<activity android:name="SettingsActivity" ... > 916 <intent-filter> 917 <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> 918 <category android:name="android.intent.category.DEFAULT" /> 919 </intent-filter> 920</activity> 921</pre> 922 923<p>Bộ lọc ý định này cho hệ thống biết rằng đây là hoạt động kiểm soát mức sử dụng dữ liệu 924của ứng dụng của bạn. Vì thế, khi người dùng kiểm tra lượng dữ liệu mà ứng dụng của bạn đang dùng từ ứng dụng 925Thiết đặt của hệ thống, sẽ có một nút <em>Xem thiết đặt ứng dụng</em> khởi chạy 926{@link android.preference.PreferenceActivity} của bạn, vì thế người dùng có thể tinh chỉnh lượng dữ liệu mà ứng dụng của bạn 927dùng.</p> 928 929 930 931 932 933 934 935<h2 id="Custom">Xây dựng một Thiết đặt Tùy chỉnh</h2> 936 937<p>Khuôn khổ Android bao gồm nhiều lớp con {@link android.preference.Preference} mà 938cho phép bạn xây dựng một UI cho một vài loại thiết đặt khác nhau. 939Tuy nhiên, bạn có thể khám phá thiết đặt mình cần mà chưa có giải pháp tích hợp sẵn, chẳng hạn như một 940bộ chọn số hay bộ chọn ngày. Trong trường hợp như vậy, bạn sẽ cần tạo một tùy chọn tùy chỉnh bằng cách mở rộng 941lớp {@link android.preference.Preference} hoặc một trong các lớp con khác.</p> 942 943<p>Khi bạn mở rộng lớp {@link android.preference.Preference}, có một vài điều quan trọng 944mà bạn cần làm:</p> 945 946<ul> 947 <li>Quy định giao diện người dùng sẽ xuất hiện khi người dùng chọn thiết đặt.</li> 948 <li>Lưu giá trị của thiết đặt khi phù hợp.</li> 949 <li>Khởi tạo {@link android.preference.Preference} bằng giá trị hiện tại (hoặc mặc định) 950khi xét tới dạng xem.</li> 951 <li>Cung cấp giá trị mặc định khi hệ thống yêu cầu.</li> 952 <li>Nếu {@link android.preference.Preference} cung cấp UI của chính mình (chẳng hạn như một hộp thoại), hãy lưu 953và khôi phục trạng thái để xử lý các thay đổi trong vòng đời (chẳng hạn như khi người dùng xoay màn hình).</li> 954</ul> 955 956<p>Các phần sau mô tả cách hoàn thành từng tác vụ này.</p> 957 958 959 960<h3 id="CustomSelected">Quy định một giao diện người dùng</h3> 961 962 <p>Nếu bạn trực tiếp mở rộng lớp {@link android.preference.Preference}, bạn cần triển khai 963{@link android.preference.Preference#onClick()} để định nghĩa hành động xảy ra khi người dùng 964chọn mục. Tuy nhiên, hầu hết các thiết đặt tùy chỉnh sẽ mở rộng {@link android.preference.DialogPreference} để 965hiển thị một hộp thoại, điều này làm đơn giản hóa quy trình. Khi bạn mở rộng {@link 966android.preference.DialogPreference}, bạn phải gọi {@link 967android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} trong khi đang ở trong 968hàm dựng lớp để quy định bố trí cho hộp thoại.</p> 969 970 <p>Ví dụ, sau đây là hàm dựng cho một {@link 971android.preference.DialogPreference} tùy chỉnh mà khai báo bố trí và quy định văn bản cho 972các nút hộp thoại tích cực và tiêu cực mặc định:</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">Lưu giá trị của thiết đặt</h3> 992 993<p>Bạn có thể lưu một giá trị cho thiết đặt vào bất cứ lúc nào bằng cách gọi một trong các phương pháp của lớp {@link 994android.preference.Preference}, {@code persist*()}, chẳng hạn như {@link 995android.preference.Preference#persistInt persistInt()} nếu giá trị của thiết đặt là một số nguyên hoặc 996{@link android.preference.Preference#persistBoolean persistBoolean()} để lưu một boolean.</p> 997 998<p class="note"><strong>Lưu ý:</strong> Mỗi {@link android.preference.Preference} chỉ có thể lưu một 999kiểu dữ liệu, vì thế bạn phải sử dụng phương pháp {@code persist*()} phù hợp cho kiểu dữ liệu được sử dụng bởi 1000{@link android.preference.Preference} tùy chỉnh của mình.</p> 1001 1002<p>Thời điểm bạn chọn duy trì thiết đặt có thể phụ thuộc vào lớp {@link 1003android.preference.Preference} nào mà bạn mở rộng. Nếu mở rộng {@link 1004android.preference.DialogPreference}, khi đó bạn nên duy trì giá trị đó chỉ khi hộp thoại 1005đóng lại do kết quả tích cực (người dùng chọn nút "OK").</p> 1006 1007<p>Khi {@link android.preference.DialogPreference} đóng lại, hệ thống sẽ gọi phương pháp {@link 1008android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Phương pháp bao gồm một 1009tham đối boolean quy định xem người dùng có trả về kết quả "tích cực" hay không—nếu kết quả là 1010<code>true</code>, khi đó, người dùng đã chọn nút tích cực và bạn nên lưu giá trị mới này. Ví 1011dụ:</p> 1012 1013<pre> 1014@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>Trong ví dụ này, <code>mNewValue</code> là một thành viên lớp lưu giữ giá trị 1024hiện tại của thiết đặt. Việc gọi {@link android.preference.Preference#persistInt persistInt()} sẽ lưu giá trị vào 1025tệp {@link android.content.SharedPreferences} (tự động sử dụng khóa mà 1026được quy định trong tệp XML cho {@link android.preference.Preference} này).</p> 1027 1028 1029<h3 id="CustomInitialize">Khởi tạo giá trị hiện tại</h3> 1030 1031<p>Khi hệ thống thêm {@link android.preference.Preference} của bạn vào màn hình, nó 1032gọi {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} để thông báo 1033với bạn xem thiết đặt có giá trị được duy trì hay không. Nếu không có giá trị được duy trì, lệnh gọi này sẽ cung cấp 1034cho bạn giá trị mặc định.</p> 1035 1036<p>Phương pháp {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} chuyển một 1037boolean, <code>restorePersistedValue</code>, để cho biết liệu giá trị đã được duy trì 1038cho thiết đặt hay không. Nếu nó là <code>true</code>, khi đó bạn nên truy xuất giá trị được duy trì bằng cách gọi 1039một trong các phương pháp của lớp {@link 1040android.preference.Preference}, {@code getPersisted*()}, chẳng hạn như {@link 1041android.preference.Preference#getPersistedInt getPersistedInt()} đối với một giá trị số nguyên. Bạn sẽ 1042thường muốn truy xuất giá trị được duy trì sao cho bạn có thể cập nhật UI cho phù hợp để phản ánh 1043giá trị đã lưu trước đó.</p> 1044 1045<p>Nếu <code>restorePersistedValue</code> là <code>false</code>, vậy bạn 1046nên sử dụng giá trị mặc định được chuyển trong tham đối thứ hai.</p> 1047 1048<pre> 1049@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>Mỗi phương pháp {@code getPersisted*()} sẽ lấy một tham đối quy định 1063giá trị mặc định sẽ sử dụng trong trường hợp thực sự không có giá trị được duy trì hoặc khóa không tồn tại. Trong 1064ví dụ trên, một hằng số cục bộ được sử dụng để quy định giá trị mặc định trong trường hợp {@link 1065android.preference.Preference#getPersistedInt getPersistedInt()} không thể trả về một giá trị được duy trì.</p> 1066 1067<p class="caution"><strong>Chú ý:</strong> Bạn <strong>không thể</strong> sử dụng 1068<code>defaultValue</code> làm giá trị mặc định trong phương pháp {@code getPersisted*()}, bởi 1069giá trị của nó luôn rỗng khi <code>restorePersistedValue</code> là <code>true</code>.</p> 1070 1071 1072<h3 id="CustomDefault">Cung cấp một giá trị mặc định</h3> 1073 1074<p>Nếu trường hợp lớp {@link android.preference.Preference} của bạn quy định một giá trị mặc định 1075(với thuộc tính {@code android:defaultValue}), khi đó hệ thống 1076sẽ gọi {@link android.preference.Preference#onGetDefaultValue 1077onGetDefaultValue()} khi nó khởi tạo đối tượng để truy xuất giá trị. Bạn phải 1078triển khai phương pháp này để hệ thống lưu giá trị mặc định trong {@link 1079android.content.SharedPreferences}. Ví dụ:</p> 1080 1081<pre> 1082@Override 1083protected Object onGetDefaultValue(TypedArray a, int index) { 1084 return a.getInteger(index, DEFAULT_VALUE); 1085} 1086</pre> 1087 1088<p>Các tham đối của phương pháp cung cấp mọi thứ bạn cần: mảng thuộc tính và vị trí chỉ mục 1089của {@code android:defaultValue} mà bạn phải truy xuất. Lý do bạn phải triển khai 1090phương pháp này nhằm trích xuất giá trị mặc định từ thuộc tính đó là bởi bạn phải quy định 1091một giá trị mặc định cục bộ cho thuộc tính trong trường hợp giá trị không được định nghĩa.</p> 1092 1093 1094 1095<h3 id="CustomSaveState">Lưu và khôi phục trạng thái của Tùy chọn</h3> 1096 1097<p>Giống như {@link android.view.View} trong một bố trí, lớp con {@link android.preference.Preference} 1098của bạn chịu trách nhiệm lưu và khôi phục trạng thái của nó trong trường hợp hoạt động hoặc phân đoạn 1099được khởi động lại (chẳng hạn như khi người dùng xoay màn hình). Để lưu và khôi phục 1100trạng thái của lớp {@link android.preference.Preference} của bạn cho đúng, bạn phải triển khai các 1101phương pháp gọi lại vòng đời {@link android.preference.Preference#onSaveInstanceState 1102onSaveInstanceState()} và {@link 1103android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p> 1104 1105<p>Trạng thái của {@link android.preference.Preference} của bạn được định nghĩa bởi một đối tượng mà triển khai 1106giao diện {@link android.os.Parcelable}. Khuôn khổ Android sẽ cung cấp một đối tượng như vậy cho bạn 1107như một điểm bắt đầu để định nghĩa đối tượng trạng thái của bạn: lớp {@link 1108android.preference.Preference.BaseSavedState}.</p> 1109 1110<p>Để định nghĩa cách thức lớp {@link android.preference.Preference} của bạn lưu trạng thái của nó 1111hãy mở rộng lớp {@link android.preference.Preference.BaseSavedState}. Bạn cần khống chế chỉ 1112 một vài phương pháp và định nghĩa đối tượng {@link android.preference.Preference.BaseSavedState#CREATOR} 1113.</p> 1114 1115<p>Đối với hầu hết ứng dụng, bạn có thể sao chép triển khai sau và chỉ cần thay đổi các dòng 1116xử lý {@code value} nếu lớp con {@link android.preference.Preference} của bạn lưu một kiểu 1117dữ liệu khác số nguyên.</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 @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<SavedState> CREATOR = 1144 new Parcelable.Creator<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>Với triển khai {@link android.preference.Preference.BaseSavedState} bên trên được thêm 1158vào ứng dụng của bạn (thường dưới dạng một lớp con của lớp con {@link android.preference.Preference} của bạn), khi đó 1159bạn cần triển khai các phương pháp {@link android.preference.Preference#onSaveInstanceState 1160onSaveInstanceState()} và {@link 1161android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} cho lớp con 1162{@link android.preference.Preference} của mình.</p> 1163 1164<p>Ví dụ:</p> 1165 1166<pre> 1167@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@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