1page.title=設定 2page.tags=偏好設定、偏好設定 Activity、偏好設定片段 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">建立偏好設定 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>重要類別</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 {@link android.preference.Preference} API 建置與其他 Android 應用程式使用者體驗一致的介面 (包含系統設定)。 73 74本文件說明如何使用 {@link android.preference.Preference} API 建置應用程式設定。 75</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} 物件建置使用者介面,而是使用您在 XML 檔案中所宣告 {@link android.preference.Preference} 類別的各種子類別來建置設定。 94 95</p> 96 97<p>一個 {@link android.preference.Preference} 物件是單一設定的建置區塊。 98每個 {@link android.preference.Preference} 都以項目的形式在清單中顯示,並為使用者提供適當的 UI 以修改設定。 99例如,{@link 100android.preference.CheckBoxPreference} 可以建立顯示核取方塊的清單項目,而 {@link 101android.preference.ListPreference} 可以建立開啟對話方塊 (其中包含選擇清單) 的項目。</p> 102 103<p>每個您新增的 {@link android.preference.Preference} 都會有一個對應的鍵值配對,系統可使用此鍵值對將設定儲存到您應用程式設定的預設 {@link android.content.SharedPreferences} 檔案。 104 105當使用者變更設定,系統會為您更新 {@link android.content.SharedPreferences} 檔案中的對應值。 106您唯一需要與關聯的 {@link android.content.SharedPreferences} 檔案直接互動的時候,是當您需要讀取值才能根據使用者設定判斷應用程式行為時。 107 108</p> 109 110<p>儲存在 {@link android.content.SharedPreferences} 的每個設定值可以是下列其中一個資料類型: 111</p> 112 113<ul> 114 <li>布林值</li> 115 <li>浮動</li> 116 <li>整數</li> 117 <li>長整數</li> 118 <li>字串</li> 119 <li>字串 {@link java.util.Set}</li> 120</ul> 121 122<p>由於您的應用程式設定 UI 是使用 {@link android.preference.Preference} 物件,而不是 {@link android.view.View} 物件建置,因此您需要使用專門的 {@link android.app.Activity} 或 {@link android.app.Fragment} 子類別來顯示清單設定: 123 124 125</p> 126 127<ul> 128 <li>如果應用程式支援的 Android 版本早於 3.0 (API 級別 10 及較早版本),您必須以 {@link android.preference.PreferenceActivity} 類別延伸的形式建置 Activity。 129</li> 130 <li>在 Android 3.0 及更新版本上,您應該使用傳統 {@link android.app.Activity},它託管了顯示應用程式設定的 {@link android.preference.PreferenceFragment}。 131 132然而,當您有多個設定群組時,還可以使用 {@link android.preference.PreferenceActivity} 在大螢幕建立兩個面板的版面配置。 133</li> 134</ul> 135 136<p>如何設定 {@link android.preference.PreferenceActivity} 和 {@link 137android.preference.PreferenceFragment} 執行個體在<a href="#Activity">建立偏好設定 Activity</a> 和<a href="#Fragment">使用偏好設定片段</a>小節中有相關說明。 138</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>為啟用或停用的設定顯示含有核取方塊的項目。儲存的值是布林值 (如果選取 <code>true</code>)。 155</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} 類別以選取數字或日期。因此,您可能需要定義自己的 {@link android.preference.Preference} 子類別。 172如需執行此操作的協助,請參閱<a href="#Custom">建置自訂偏好設定</a>。</p> 173 174 175 176<h2 id="DefiningPrefs">在 XML 中定義偏好設定</h2> 177 178<p>雖然您可以在執行階段將新的 {@link android.preference.Preference} 物件具現化,但您仍應該在 XML 中定義設定清單,並在其中包含 {@link android.preference.Preference} 物件的階層。 179 180使用 XML 檔案定義設定集合是較建議的做法,因為該檔案提供的易讀結構很容易更新。 181而且,雖然您仍然可以在執行階段修改集合,但您的應用程式設定通常是預先定義好的。 182</p> 183 184<p>每個 {@link android.preference.Preference} 子類別都可透過與類別名稱相符的 XML 元素進行宣告,例如 {@code <CheckBoxPreference>}。 185</p> 186 187<p>您必須將 XML 檔案儲存在 {@code res/xml/} 目錄中。雖然您可以自由命名檔案,但在傳統上會命名為 {@code preferences.xml}。 188您通常只需要一個檔案,因為階層 (會開啟自己的設定清單) 中的子目錄是透過 {@link android.preference.PreferenceScreen} 的巢狀執行個體進行宣告。 189 190</p> 191 192<p class="note"><strong>注意:</strong>如果您想要為設定建立多個面板的版面配置,則您需要為每個片段準備個別的 XML 檔案。 193</p> 194 195<p>XML 檔案的根節點必須是 {@link android.preference.PreferenceScreen 196<PreferenceScreen>} 元素。您要將每個 {@link 197android.preference.Preference} 新增到此元素內。您在 {@link android.preference.PreferenceScreen <PreferenceScreen>} 元素內新增的每個子項會在設定清單中顯示為單一項目。 198 199</p> 200 201<p>例如:</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>此範例中有一個 {@link android.preference.CheckBoxPreference} 和一個 {@link 223android.preference.ListPreference}。這兩個項目都包含下列三個屬性:</p> 224 225<dl> 226 <dt>{@code android:key}</dt> 227 <dd>需要這個屬性才能保留資料值的偏好設定。它會指定當系統將此設定值儲存於 {@link 228android.content.SharedPreferences} 時要使用的唯一索引鍵 (字串)。 229 230 <p>只有在下列情況下不需要此屬性:<em></em>偏好設定為 {@link android.preference.PreferenceCategory} 或 {@link android.preference.PreferenceScreen},或者偏好設定指定 {@link android.content.Intent} 進行呼叫 (搭配 <a href="#Intents">{@code <intent>}</a> 元素) 或 {@link android.app.Fragment} 進行顯示 (搭配 <a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code 231android:fragment}</a> 屬性)。 232 233</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 <PreferenceCategory>} 元素指定。 <br/><b>2.</b>標題以 {@code android:title} 屬性指定。 252</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>您可以使用上述一種或兩種分組技巧來整理您的應用程式設定。決定要使用哪種方法或如何分割設定時,您應該要依照 Android 設計<a href="{@docRoot}design/patterns/settings.html">設定</a>指南中的指導方針進行。 274 275</p> 276 277 278<h4 id="Titles">使用標題</h4> 279 280<p>如果您想要在設定群組間使用標題區分 (如圖 2 所示),將 {@link android.preference.Preference} 物件的每個群組放入 {@link 281android.preference.PreferenceCategory}。 282</p> 283 284<p>例如:</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">使用子畫面</h4> 313 314<p>如果您想將設定群組放入子畫面 (如圖 3 所示),將 {@link android.preference.Preference} 物件的群組放入 {@link 315android.preference.PreferenceScreen}。 316</p> 317 318<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" /> 319<p class="img-caption"><strong>圖 3.</strong>設定子畫面。{@code 320<PreferenceScreen>} 元素建立的項目會在選取時開啟獨立的清單以顯示巢狀設定。 321</p> 322 323<p>例如:</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">使用意圖</h3> 354 355<p>在某些情況下,您可能會希望偏好設定項目開啟不同的 Activity 而不是設定畫面,例如,開啟網路瀏覽器以檢視網頁。 356如要在使用者選取偏好設定項目時呼叫 {@link 357android.content.Intent},請新增 {@code <intent>} 元素做為對應 {@code <Preference>} 元素的子項。 358</p> 359 360<p>例如,您可以使用下列方法透過偏好設定項目開啟網頁:</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>您可以使用下列屬性建立隱含和明確意圖:</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>根據 {@link android.content.Intent#setType setType()} 方法指派的 MIME 類型。 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">建立偏好設定 Activity</h2> 391 392<p>如要在 Activity 中顯示設定,延伸 {@link 393android.preference.PreferenceActivity} 類別。這是傳統 {@link 394android.app.Activity} 類別的延伸,可根據 {@link 395android.preference.Preference} 物件的階層顯示設定清單。當使用者進行變更時,{@link android.preference.PreferenceActivity} 會自動保留與每個 {@link 396android.preference.Preference} 關聯的設定。 397</p> 398 399<p class="note"><strong>注意:</strong>如果您針對 Android 3.0 及更新版本開發應用程式,您應該改為使用 {@link android.preference.PreferenceFragment}。 400前往下一個<a href="#Fragment">使用偏好設定片段</a>章節。 401</p> 402 403<p>最需要注意的一件事就是,不要在 {@link 404android.preference.PreferenceActivity#onCreate onCreate()} 呼叫期間載入檢視的版面配置。您應該要呼叫 {@link 405android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()},將您在 XML 檔案中宣告的偏好設定新增到 Activity 中。 406例如,下列為功能 {@link android.preference.PreferenceActivity} 所需的基本程式碼: 407</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>事實上,這個程式碼對某些應用程式而言已經足夠,因為使用者修改偏好設定後,系統會將變更儲存到預設 {@link android.content.SharedPreferences} 檔案,當您需要檢查使用者設定時,您的其他應用程式元件就能進行讀取。 420 421但是,許多應用程式需要更多一點程式碼,以接聽對偏好設定進行的變更。 422如需在 {@link android.content.SharedPreferences} 檔案接聽變更的相關資訊,請參閱<a href="#ReadingPrefs">讀取偏好設定</a>。 423 424</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} 新增到任何 Activity — 您不需要使用 {@link android.preference.PreferenceActivity}。 434</p> 435 436<p><a href="{@docRoot}guide/components/fragments.html">片段</a>單就 Activity 而言,可為您的應用程式提供更有彈性的架構,無論您建置哪一種 Activity 都一樣。 437 438因此,我們建議您盡可能使用 {@link 439android.preference.PreferenceFragment} 來控制設定的顯示,而不要使用 {@link 440android.preference.PreferenceActivity}。</p> 441 442<p>實作 {@link android.preference.PreferenceFragment} 可以很簡單,只要定義 {@link android.preference.PreferenceFragment#onCreate onCreate()} 方法,透過 {@link android.preference.PreferenceFragment#addPreferencesFromResource 443addPreferencesFromResource()} 載入偏好設定檔案。 444 445例如:</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>之後,您可以將此片段新增至 {@link android.app.Activity},做法與任何其他 461{@link android.app.Fragment} 一樣。例如:</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>注意:</strong>{@link android.preference.PreferenceFragment} 沒有自己的 {@link android.content.Context} 物件。 478如果您需要 {@link android.content.Context} 物件,可以呼叫 {@link android.app.Fragment#getActivity()}。 479不過,必須小心,只能在片段附加到 Activity 時才能呼叫 {@link android.app.Fragment#getActivity()}。 480如果未附加片段,或是在生命週期期間中斷連結,{@link 481android.app.Fragment#getActivity()} 將傳回 null。 482</p> 483 484 485<h2 id="Defaults">設定預設值</h2> 486 487<p>您建立的偏好設定可能為應用程式定義了一些重要的行為,因此當使用者第一次開啟您的應用程式時,務必使用每個 {@link android.preference.Preference} 預設值來初始化關聯的 {@link android.content.SharedPreferences} 檔案。 488 489 490</p> 491 492<p>您必須要做的第一件事,就是使用 {@code android:defaultValue} 屬性指定 XML 檔案中每個 {@link 493android.preference.Preference} 物件的預設值。 494值可以是適用於對應 {@link android.preference.Preference} 物件的任何資料類型。 495例如: 496</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>之後,從您應用程式主 Activity — 以及使用者第一次進入您應用程式所使用的任何其他 Activity — 的 {@link android.app.Activity#onCreate onCreate()} 方法呼叫 {@link android.preference.PreferenceManager#setDefaultValues 511setDefaultValues()}: 512 513</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>,系統只會在過去從未呼叫此方法時設定預設值 (或者預設值共用偏好設定檔案的 {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} 為 false)。 530 531</p></li> 532</ul> 533 534<p>只要將第三個引數設為 <code>false</code>,您可以在每次 Activity 啟動時很安全地呼叫此方法,而不會將使用者儲存的偏好設定重設為預設值。 535 536不過,如果您將它設為 <code>true</code>,會將任何之前的值覆寫為預設值。 537</p> 538 539 540 541<h2 id="PreferenceHeaders">使用偏好設定標頭</h2> 542 543<p>在少數情況下,您可能會想將設定設計為只在第一個畫面顯示<a href="#Subscreens">子畫面</a>清單(與系統設定應用程式一樣,如圖 4 和 5 所示)。 544 545當您為 Android 3.0 及更新版本開發這類設計時,您應該使用 Android 3.0 的新「標頭」功能,而不是使用巢狀 {@link android.preference.PreferenceScreen} 元素建置子畫面。 546 547</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>使用這個設計最大的好處在於在大螢幕執行時, 563{@link android.preference.PreferenceActivity} 會自動顯示兩個面板的版面配置,如圖 4 所示。</p> 564 565<p>即使應用程式支援的 Android 版本較 3.0 舊,您還是可以建置應用程式在新版的裝置上使用 {@link android.preference.PreferenceFragment} 顯示兩個面板,同時仍然支援舊版裝置上的傳統多畫面階層 (請參閱<a href="#BackCompatHeaders">使用偏好設定標頭支援舊版</a>)。 566 567 568 569</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>標頭以 XML 標頭檔案定義。 573 <br/><b>2.</b>每個設定群組是由標頭檔案 {@code <header>} 元素指定的{@link android.preference.PreferenceFragment} 所定義。 574 575</p> 576 577<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" /> 578<p class="img-caption"><strong>圖 5.</strong>含設定標頭的手機裝置。選取項目後,關聯的 {@link android.preference.PreferenceFragment} 會取代標頭。 579 580</p> 581 582 583<h3 id="CreateHeaders" style="clear:left">建立標頭檔案</h3> 584 585<p>您標頭清單中的每個設定群組是由根 {@code <preference-headers>} 元素中的單一 {@code <header>} 元素指定。 586例如:</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>有了 {@code android:fragment} 屬性,每個標頭會宣告當使用者選取標頭時,應該開啟的 {@link 606android.preference.PreferenceFragment} 執行個體。</p> 607 608<p>{@code <extras>} 元素可讓您將鍵值配對傳送到 {@link 609android.os.Bundle} 中的片段。片段可以透過呼叫 {@link 610android.app.Fragment#getArguments()} 擷取引數。您可以因各種理由將引數傳送到片段,但其中一個最好的理由是針對每個群組重複使用 {@link 611android.preference.PreferenceFragment} 中相同的子類別,並使用引數指定應載入片段的偏好設定 XML 檔案。 612 613</p> 614 615<p>例如,當每個標頭使用 {@code "settings"} 索引鍵定義 {@code <extra>} 引數時,下列片段可在多個設定群組重複使用: 616</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">顯示標頭</h3> 637 638<p>如要顯示偏好設定標頭,必須實作 {@link 639android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} 回呼方法,並呼叫 {@link android.preference.PreferenceActivity#loadHeadersFromResource 640loadHeadersFromResource()}。 641例如:</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>當使用者從標頭清單選取項目時,系統會開啟關聯的 {@link 653android.preference.PreferenceFragment}。</p> 654 655<p class="note"><strong>注意:</strong>使用偏好設定標頭時,{@link 656android.preference.PreferenceActivity} 的子類別不需要實作 {@link 657android.preference.PreferenceActivity#onCreate onCreate()} 方法,這是因為 Activity 唯一需要做的工作就是載入標頭。 658</p> 659 660 661<h3 id="BackCompatHeaders">使用偏好設定標頭支援舊版</h3> 662 663<p>如果您應用程式支援的 Android 版本比 3.0 舊,您仍然可以在 Android 3.0 及更新版本執行時,使用標頭提供兩個面板的版面配置。 664您只需要建立一個額外的偏好設定 XML 檔案,該檔案要使用行為與標頭項目 (供舊版 Android 使用) 一樣的基本 {@link android.preference.Preference 665<Preference>} 元素。 666 667</p> 668 669<p>但是,不會開啟新的 {@link android.preference.PreferenceScreen},每個 {@link 670android.preference.Preference <Preference>} 元素會傳送一個 {@link android.content.Intent} 到 {@link android.preference.PreferenceActivity},以指定要載入的偏好設定 XML 檔案。 671 672</p> 673 674<p>例如,下列為使用 Android 3.0及更新版本的偏好設定標頭 XML 檔案 ({@code res/xml/preference_headers.xml}): 675</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>而,這裡有個偏好設定檔案為 Android 3.0 以下版本提供相同的標頭 ({@code res/xml/preference_headers_legacy.xml}): 691</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>因為 Android 3.0 已加入對 {@code <preference-headers>} 的支援,系統只會在 Androd 3.0 或更新版本執行時,才會呼叫 {@link 715android.preference.PreferenceActivity} 中的 {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()}。 716如要載入「舊版」標頭檔案 ({@code preference_headers_legacy.xml}),您必須檢查 Android 版本,如果版本比 Android 3.0 更舊 ({@link 717android.os.Build.VERSION_CODES#HONEYCOMB}),呼叫 {@link 718android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} 以載入舊版標頭檔案。 719 720 721例如:</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>最後一件要做的事,是處理傳送到 Activity 的 {@link android.content.Intent},以識別要載入的偏好設定檔案。 743擷取意圖的動作,並將它與偏好設定 XML {@code <intent>} 標籤中使用的已知動作字串進行比對: 744</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>請注意,{@link 768android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} 的連續呼叫會將所有偏好設定堆疊在單一清單中,因此請確定將條件鏈結到 else-if 陳述式時只會呼叫它一次。 769 770</p> 771 772 773 774 775 776<h2 id="ReadingPrefs">讀取偏好設定</h2> 777 778<p>根據預設,透過呼叫靜態方法 {@link 779android.preference.PreferenceManager#getDefaultSharedPreferences 780PreferenceManager.getDefaultSharedPreferences()},您應用程式中的所有偏好設定會儲存可從應用程式內任何地方存取的檔案中。 781這會傳回 {@link 782android.content.SharedPreferences} 物件,其中包含與您 {@link 783android.preference.PreferenceActivity} 使用之 {@link android.preference.Preference} 物件關聯的所有鍵值配對。 784</p> 785 786<p>例如,下列說明如何從應用程式中的任何其他 Activity 讀取其中一個偏好設定值: 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如要在任何偏好設定發生變更時收到回呼,實作 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener 800SharedPreference.OnSharedPreferenceChangeListener} 介面,並呼叫 {@link 801android.content.SharedPreferences#registerOnSharedPreferenceChangeListener 802registerOnSharedPreferenceChangeListener()} 為 {@link android.content.SharedPreferences} 物件註冊接聽器。 803 804</p> 805 806<p>介面只有一個回呼方式 {@link 807android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged 808onSharedPreferenceChanged()},而且在 Activity 中實作介面可能對您來說會更為容易。 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>在此範例中,方法會檢查是否是針對已知的偏好設定索引鍵設定進行變更。它會呼叫 {@link android.preference.PreferenceActivity#findPreference findPreference()} 以取得變更的 {@link android.preference.Preference} 物件,以便將項目摘要修改為使用者選取的描述。 829 830 831也就是說,當設定為 {@link 832android.preference.ListPreference} 或其他多選擇設定時,如果設定變更為顯示目前狀態 (如圖 5 顯示的休眠設定),您應該呼叫 {@link 833android.preference.Preference#setSummary setSummary()}。 834</p> 835 836<p class="note"><strong>注意:</strong>如 Android 設計文件中有關<a href="{@docRoot}design/patterns/settings.html">設定</a>的說明所述,我們建議您在每次使用者變更偏好設定時更新 {@link android.preference.ListPreference} 的摘要,以描述目前的設定。 837 838</p> 839 840<p>為了在 Activity 中正確管理生命週期,我們建議您分別在 {@link 841android.app.Activity#onResume} 和 {@link android.app.Activity#onPause} 回呼期間,註冊和解決註冊您的 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener}: 842</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>注意:</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} 新增所需的偏好設定以控制應用程式的資料習慣後,您應該在宣示說明檔新增 {@link 911android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} 的意圖篩選器。 912例如:</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>這個意圖篩選器向系統指出,是 Activity 在控制您的應用程式資料使用量。 924因此,當使用者從系統設定應用程式檢查您的應用程式使用了多少資料量時,可以使用 [檢視應用程式設定] 按鈕啟動您的<em></em> {@link android.preference.PreferenceActivity},讓使用者精簡您應用程式使用的資料量。 925 926 927</p> 928 929 930 931 932 933 934 935<h2 id="Custom">建置自訂偏好設定</h2> 936 937<p>Android 架構包含各式各樣的 {@link android.preference.Preference} 子類別,可讓您建置所種不同設定類型的 UI。不過,您可能會發現內建解決方案中可能沒有您所需的設定,例如數字挑選器或日期挑選器。 938 939 940在這類情況下,您需要延伸 {@link android.preference.Preference} 類別或其中一個其他子類別,以建立自訂的偏好設定。 941</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} 類別,必須實作 {@link android.preference.Preference#onClick()} 以定義使用者選取項目時的動作。 963 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()},或者使用 {@link android.preference.Preference#persistBoolean persistBoolean()} 儲存布林值。 996</p> 997 998<p class="note"><strong>注意:</strong>每個 {@link android.preference.Preference} 只能儲存一個資料類型,因此您必須使用適合您自訂 {@link android.preference.Preference} 使用之資料類型的 {@code persist*()} 方法。 999 1000</p> 1001 1002<p>當您選擇保留設定時,可以依據您延伸的 {@link 1003android.preference.Preference} 類別加以設定。如果您延伸 {@link 1004android.preference.DialogPreference},則應該只在對話方塊因正值結果 (使用者選取 [確定] 按鈕) 關閉時保留該值。 1005</p> 1006 1007<p>當 {@link android.preference.DialogPreference} 關閉時,系統會呼叫 {@link 1008android.preference.DialogPreference#onDialogClosed onDialogClosed()} 方法。這個方法包括一個布林值引數,指定使用者結果是否為「正值」— 如果值為 1009<code>true</code>,則表示使用者選取正值按鈕,而您應該儲存新值。 1010例如: 1011</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>在此範例中,<code>mNewValue</code> 是保留設定目前值的類別成員。 1024呼叫 {@link android.preference.Preference#persistInt persistInt()} 可將值儲存到 {@link android.content.SharedPreferences} 檔案 (自動使用 XML 檔案中為此 {@link android.preference.Preference} 指定的索引鍵)。 1025 1026</p> 1027 1028 1029<h3 id="CustomInitialize">初始化目前值</h3> 1030 1031<p>當系統將您的 {@link android.preference.Preference} 新增到畫面時,會呼叫 {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} 以通知您設定是否有持續值。 1032 1033如果沒有持續值,這個呼叫會提供您預設值。 1034</p> 1035 1036<p>{@link android.preference.Preference#onSetInitialValue onSetInitialValue()} 方法會傳送布林值 <code>restorePersistedValue</code>,以指出該設定的值是否已經持續。 1037 1038如果是 <code>true</code>,則您應該呼叫其中一個 {@link 1039android.preference.Preference} 類別的 {@code getPersisted*()} 方法以擷取持續值,例如,如果為整數值,可使用 {@link 1040android.preference.Preference#getPersistedInt getPersistedInt()}。 1041您通常都會想要擷取持續值,如此您可以正確的更新 UI 以反映之前儲存的值。 1042 1043</p> 1044 1045<p>如果 <code>restorePersistedValue</code> 是 <code>false</code>,則您應該使用在第二引數中傳送的預設值。 1046</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>在實際上沒有持續值或沒有索引鍵的情況下,每個 {@code getPersisted*()} 方法會採用指定要使用之預設值的引數。 1063在上述範例中,會使用本機常數來指定預設值,以避免 {@link 1064android.preference.Preference#getPersistedInt getPersistedInt()} 無法傳回持續值。 1065</p> 1066 1067<p class="caution"><strong>注意:</strong>您<strong>無法</strong>使用 <code>defaultValue</code> 作為 {@code getPersisted*()} 方法中的預設值,因為當 <code>restorePersistedValue</code> 為 <code>true</code> 時,其值永遠是 null。 1068 1069</p> 1070 1071 1072<h3 id="CustomDefault">提供預設值</h3> 1073 1074<p>如果 {@link android.preference.Preference} 類別的執行個體指定預設值 (包含 {@code android:defaultValue} 屬性),則系統會在將物件具現化時呼叫 {@link android.preference.Preference#onGetDefaultValue 1075onGetDefaultValue()},以擷取值。 1076 1077您必須實作此方法,才能讓系統將預設值儲存在 {@link 1078android.content.SharedPreferences} 中。 1079例如:</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>方法引數可以提供您所需的所有物件:屬性陣列,以及您必須擷取之 {@code android:defaultValue} 的索引位置。 1089您必須實作此方法以便從屬性擷取預設值的原因,是因為您必須在未定義值的情況為屬性指定一個本機預設值。 1090 1091</p> 1092 1093 1094 1095<h3 id="CustomSaveState">儲存和還原偏好設定狀態</h3> 1096 1097<p>如同版面配置中的 {@link android.view.View},您的 {@link android.preference.Preference} 子類別負責在 Activity 或片段重新啟動 (例如,當使用者旋轉螢幕時) 時,儲存和還原其狀態。 1098 1099如要正確的儲存和還原 {@link android.preference.Preference} 類別的狀態,您必須實作生命週期回呼方法 {@link android.preference.Preference#onSaveInstanceState 1100onSaveInstanceState()} 和 {@link 1101android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}。 1102 1103</p> 1104 1105<p>您 {@link android.preference.Preference} 的狀態由實作 {@link android.os.Parcelable} 介面的物件定義。 1106Android 架構為您提供這類物件作為定義狀態物件的起始點:{@link 1107android.preference.Preference.BaseSavedState} 類別。 1108</p> 1109 1110<p>如要定義 {@link android.preference.Preference} 類別儲存狀態的方法,您應該延伸 {@link android.preference.Preference.BaseSavedState} 類別。 1111您只需要覆寫幾個方法,然後定義 {@link android.preference.Preference.BaseSavedState#CREATOR}物件。 1112 1113</p> 1114 1115<p>對於大多數應用程式而言,如果您的 {@link android.preference.Preference} 子類別儲存整數以外的資料類型,您可以複製下列實作,然後變更處理 {@code value} 的行即可。 1116 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 @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>將上述 {@link android.preference.Preference.BaseSavedState} 實作新增到您的應用程式 (通常做為 {@link android.preference.Preference} 子類別的子類別) 之後,您需要針對 {@link android.preference.Preference} 子類別實作 {@link android.preference.Preference#onSaveInstanceState 1158onSaveInstanceState()} 和 {@link 1159android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} 方法。 1160 1161 1162</p> 1163 1164<p>例如:</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