page.title=Thiết đặt page.tags=preference,preferenceactivity,preferencefragment @jd:body

Trong tài liệu này

  1. Tổng quan
    1. Tùy chọn
  2. Định nghĩa Tùy chọn trong XML
    1. Tạo nhóm thiết đặt
    2. Sử dụng ý định
  3. Tạo một Hoạt động Tùy chọn
  4. Sử dụng Phân đoạn Tùy chọn
  5. Thiết đặt Giá trị Mặc định
  6. Sử dụng Tiêu đề Tùy chọn
    1. Tạo tệp tiêu đề
    2. Hiển thị tiêu đề
    3. Hỗ trợ các phiên bản cũ hơn với tiêu đề tùy chọn
  7. Đọc Tùy chọn
    1. Theo dõi thay đổi tùy chọn
  8. Quản lý Sử dụng Mạng
  9. Xây dựng một Thiết đặt Tùy chỉnh
    1. Quy định một giao diện người dùng
    2. Lưu giá trị của thiết đặt
    3. Khởi tạo giá trị hiện tại
    4. Cung cấp một giá trị mặc định
    5. Lưu và khôi phục trạng thái của Tùy chọn

Lớp khóa

  1. {@link android.preference.Preference}
  2. {@link android.preference.PreferenceActivity}
  3. {@link android.preference.PreferenceFragment}

Xem thêm

  1. Hướng dẫn thiết kế Thiết đặt

Ứ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í dụ, 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 ứng dụng sẽ đồng bộ dữ liệu với đám mây.

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 các API {@link android.preference.Preference} của Android để xây dựng một giao diện phù hợp với trả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ả cá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}.

Thiết kế Thiết đặt

Để 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ế Thiết đặt.

Hình 1. Ảnh chụp màn hình từ thiết đặt của ứng dụng Messaging trên Android. Chọn một mục được định nghĩa bởi một {@link android.preference.Preference} sẽ mở ra một giao diện để thay đổi thiết đặt.

Tổng quan

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 xâ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 khai báo trong một tệp XML.

Đối tượng {@link android.preference.Preference} là một khối dựng cho một thiết đặt đơ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 UI phù hợp để người dùng sửa đổi thiết đặt. Ví dụ, một {@link android.preference.CheckBoxPreference} tạo một mục danh sách hiển thị một hộp kiểm, và một {@link android.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.

Mỗi {@link android.preference.Preference} mà bạn thêm có một cặp khóa-giá trị tương ứng mà hệ thống sử dụng để lưu thiết đặt trong một tệp {@link android.content.SharedPreferences} mặ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ị tương ứng trong tệp {@link android.content.SharedPreferences} cho bạn. Lần duy nhất mà bạn nên trực tiếp tương tác với tệp {@link android.content.SharedPreferences} được liên kết đó là khi bạn cầ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.

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 sau:

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} thay vì đối tượng {@link android.view.View}, bạn nên sử dụng một lớp con {@link android.app.Activity} hoặc {@link android.app.Fragment} chuyên dụng để hiển thị thiết đặt danh sách:

Cách thiết đặt {@link android.preference.PreferenceActivity} của bạn và các thực thể của {@link android.preference.PreferenceFragment} được trình bày trong các phần về Tạo một Hoạt động Tùy chọnSử dụng Phân đoạn Tùy chọn.

Tùy chọn

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 android.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 quy đị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 cá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 Messaging. 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 android.preference.Preference} khác nhau.

Sau đây là một số tùy chọn phổ biến nhất:

{@link android.preference.CheckBoxPreference}
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ị được lưu là một boolean (true nếu nó được chọn).
{@link android.preference.ListPreference}
Mở một hộp thoại kèm danh sách nút chọn một. Giá trị được lưu có thể là bất kỳ loại giá trị được hỗ trợ nào (liệt kê bên trên).
{@link android.preference.EditTextPreference}
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 java.lang.String}.

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 tương ứng của chúng.

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 lớ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 android.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 lớ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ề Xây dựng Thiết đặt Tùy chỉnh.

Định nghĩa Tùy chọn trong XML

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 nê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} . 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 cung 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 xá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.

Mỗi lớp con {@link android.preference.Preference} có thể được khai báo bằng một phần tử XML mà khớp với tên lớp đó, chẳng hạn như {@code <CheckBoxPreference>}.

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à bấ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, bở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ể lồng nhau của {@link android.preference.PreferenceScreen}.

Lưu ý: Nếu bạn muốn tạo một bố trí đa bảng cho thiết đặt củ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.

Node gốc cho tệp XML phải là một phần tử {@link android.preference.PreferenceScreen <PreferenceScreen>}. Trong phần tử này là nơi bạn thêm từng {@link android.preference.Preference}. Từng phần tử con mà bạn thêm vào trong phần tử {@link android.preference.PreferenceScreen <PreferenceScreen>} sẽ xuất hiện như một mục đơn lẻ trong danh sách thiết đặt.

Ví dụ:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <CheckBoxPreference
        android:key="pref_sync"
        android:title="@string/pref_sync"
        android:summary="@string/pref_sync_summ"
        android:defaultValue="true" />
    <ListPreference
        android:dependency="pref_sync"
        android:key="pref_syncConnectionType"
        android:title="@string/pref_syncConnectionType"
        android:dialogTitle="@string/pref_syncConnectionType"
        android:entries="@array/pref_syncConnectionTypes_entries"
        android:entryValues="@array/pref_syncConnectionTypes_values"
        android:defaultValue="@string/pref_syncConnectionTypes_default" />
</PreferenceScreen>

Trong ví dụ này, có một {@link android.preference.CheckBoxPreference} và một {@link android.preference.ListPreference}. Cả hai mục đều bao gồm ba thuộc tính sau:

{@code android:key}
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 (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 android.content.SharedPreferences}.

Các thực thể duy nhất mà thuộc tính này không được yêu cầu là khi tùy chọn là một {@link android.preference.PreferenceCategory} hoặc {@link android.preference.PreferenceScreen}, hoặc tùy chọn quy định một {@link android.content.Intent} để gọi ra (bằng phần tử {@code <intent>}) hoặc {@link android.app.Fragment} để hiển thị (bằng thuộc tính {@code android:fragment}).

{@code android:title}
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.
{@code android:defaultValue}
Nó quy định giá trị ban đầu mà hệ thống nên đặt trong tệp {@link android.content.SharedPreferences}. Bạn nên cung cấp một giá trị mặc định cho tất cả thiết đặt.

Để 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 android.preference.Preference} (và lớp con tương ứng).

Hình 2. Thiết đặt thể loại có tiêu đề.
1. Thể loại được quy định bởi phần tử {@link android.preference.PreferenceCategory <PreferenceCategory>}.
2. Tiêu đề được quy định bằng thuộc tính {@code android:title}.

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 đề để định nghĩa các nhóm thiết đặt hoặc hiển thị các nhóm đó trong một màn hình riêng. Những tùy chọn này được mô tả trong các phần sau.

Tạo nhóm thiết đặt

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 có 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 chia 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 danh 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:

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 quyế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 Thiết đặt của Thiết kế Android.

Sử dụng tiêu đề

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), hãy đặt từng nhóm đối tượng {@link android.preference.Preference} vào bên trong một {@link android.preference.PreferenceCategory}.

Ví dụ:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory 
        android:title="@string/pref_sms_storage_title"
        android:key="pref_key_storage_settings">
        <CheckBoxPreference
            android:key="pref_key_auto_delete"
            android:summary="@string/pref_summary_auto_delete"
            android:title="@string/pref_title_auto_delete"
            android:defaultValue="false"... />
        <Preference 
            android:key="pref_key_sms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_sms_delete"... />
        <Preference 
            android:key="pref_key_mms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_mms_delete" ... />
    </PreferenceCategory>
    ...
</PreferenceScreen>

Sử dụng màn hình con

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 các đối tượng {@link android.preference.Preference} vào bên trong một {@link android.preference.PreferenceScreen}.

Hình 3. Màn hình con thiết đặt. Phần tử {@code <PreferenceScreen>} sẽ tạo mộ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.

Ví dụ:

<PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- opens a subscreen of settings -->
    <PreferenceScreen
        android:key="button_voicemail_category_key"
        android:title="@string/voicemail"
        android:persistent="false">
        <ListPreference
            android:key="button_voicemail_provider_key"
            android:title="@string/voicemail_provider" ... />
        <!-- opens another nested subscreen -->
        <PreferenceScreen
            android:key="button_voicemail_setting_key"
            android:title="@string/voicemail_settings"
            android:persistent="false">
            ...
        </PreferenceScreen>
        <RingtonePreference
            android:key="button_voicemail_ringtone_key"
            android:title="@string/voicemail_ringtone_title"
            android:ringtoneType="notification" ... />
        ...
    </PreferenceScreen>
    ...
</PreferenceScreen>

Sử dụng ý định

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 mà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 android.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>} làm con của phần tử {@code <Preference>} tương ứng.

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:

<Preference android:title="@string/prefs_web_page" >
    <intent android:action="android.intent.action.VIEW"
            android:data="http://www.example.com" />
</Preference>

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:

{@code android:action}
Hành động cần gán, theo mỗi phương pháp {@link android.content.Intent#setAction setAction()} .
{@code android:data}
Dữ liệu cần gán, theo mỗi phương pháp {@link android.content.Intent#setData setData()}.
{@code android:mimeType}
Kiểu MIME cần gán, theo mỗi phương pháp {@link android.content.Intent#setType setType()} .
{@code android:targetClass}
Phần lớp của tên thành phần, theo mỗi phương pháp {@link android.content.Intent#setComponent setComponent()}.
{@code android:targetPackage}
Phần gói của tên thành phần, theo mỗi phương pháp {@link android.content.Intent#setComponent setComponent()}.

Tạo một Hoạt động Tùy chọn

Để hiển thị thiết đặt của bạn trong một hoạt động, hãy mở rộng lớp {@link android.preference.PreferenceActivity}. Đây là phần mở rộng của lớp {@link android.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 android.preference.Preference}. {@link android.preference.PreferenceActivity} sẽ tự động duy trì các thiết đặt liên kết với từng {@link android.preference.Preference} khi người dùng thực hiện một thay đổi.

Lưu ý: 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à cao hơn, thay vào đó bạn nên sử dụng {@link android.preference.PreferenceFragment}. Đi đến phần tiếp theo về Sử dụng Phân đoạn Tùy chọn.

Đ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 android.preference.PreferenceActivity#onCreate onCreate()}. Thay vào đó, bạn hãy gọi {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} để thê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 cần thiết cho một {@link android.preference.PreferenceActivity} chức năng:

public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

Đâ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, hệ thống sẽ lưu thay đổi đối với tệp {@link android.content.SharedPreferences} mặc định mà các thà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, nhiề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 đó. Để biết thông tin về việc theo dõi thay đổi trong tệp {@link android.content.SharedPreferences}, hãy xem phần về Đọc Tùy chọn.

Sử dụng Phân đoạn Tùy chọn

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 android.preference.PreferenceFragment} để hiển thị danh sách các đối tượng {@link android.preference.Preference} củ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 sử dụng {@link android.preference.PreferenceActivity}.

Phân đoạn cung cấp một kiến trúc linh 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 mà bạn đang xây dựng là gì. Như vậy, chúng tôi gợi ý bạn sử dụng {@link android.preference.PreferenceFragment} để kiểm soát hiển thị các thiết đặt của mình thay cho {@link android.preference.PreferenceActivity} khi có thể.

Việc triển khai {@link android.preference.PreferenceFragment} có thể chỉ đơn giản như định nghĩa phương pháp {@link android.preference.PreferenceFragment#onCreate onCreate()} để tải một tệp tùy chọn bằng {@link android.preference.PreferenceFragment#addPreferencesFromResource addPreferencesFromResource()}. Ví dụ:

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
    }
    ...
}

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ỳ {@link android.app.Fragment} nào khác. Ví dụ:

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Display the fragment as the main content.
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
    }
}

Lưu ý: {@link android.preference.PreferenceFragment} không có một đố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} , bạn có thể gọi {@link android.app.Fragment#getActivity()}. Tuy nhiên, hãy chắc chắn là chỉ gọi {@link android.app.Fragment#getActivity()} khi phân đoạn đó được gắn kèm với một hoạt động. Khi phâ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 android.app.Fragment#getActivity()} sẽ trả về rỗng.

Thiết đặt Giá trị Mặc định

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ế bạn cần phải khởi tạo tệp {@link android.content.SharedPreferences} kèm theo với các giá trị mặc định cho từng {@link android.preference.Preference} khi người dùng lần đầu mở ứng dụng của bạn.

Đ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 android.preference.Preference} trong 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 dữ liệu nào mà phù hợp với đối tượng {@link android.preference.Preference} tương ứng. Ví dụ:

<!-- default value is a boolean -->
<CheckBoxPreference
    android:defaultValue="true"
    ... />

<!-- default value is a string -->
<ListPreference
    android:defaultValue="@string/pref_syncConnectionTypes_default"
    ... />

Khi đó, từ phương pháp {@link android.app.Activity#onCreate onCreate()} trong hoạt động chính —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 đầu tiên—hãy gọi {@link android.preference.PreferenceManager#setDefaultValues setDefaultValues()}:

PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);

Việc gọi này trong khi {@link android.app.Activity#onCreate onCreate()} sẽ đảm bảo rằng ứ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 đọ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 mạng di động hay không).

Phương pháp này dùng ba tham đối:

Miễn là bạn đặt tham đối thứ ba này thành false, bạn có thể gọi phương pháp này một cách an toàn mỗ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 mặc định. Tuy nhiên, nếu bạn đặt nó thành true, bạn sẽ khống chế mọi giá trị trước đó bằng các giá trị mặc định.

Sử dụng Tiêu đề Tùy chọn

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 chỉ hiển thị một danh sách các màn hình con (chẳng hạn như trong ứng dụng Thiết đặt của hệ thống, như 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 nê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ử {@link android.preference.PreferenceScreen} lồng nhau.

Để xây dựng thiết đặt có tiêu đề của mình, bạn cần:

  1. Tách riêng từng nhóm thiết đặt thành các thực thể riêng của {@link android.preference.PreferenceFragment}. Cụ thể, mỗi nhóm thiết đặt cần một tệp XML riêng.
  2. 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 chứa danh sách thiết đặt tương ứng.
  3. Mở rộng lớp {@link android.preference.PreferenceActivity} để lưu trữ các thiết đặt của bạn.
  4. Triển khai lệnh gọi lại {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} để quy định tệp tiêu đề.

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} tự độ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.

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 của mình để sử dụng {@link android.preference.PreferenceFragment} cho một trình chiếu hai bảng trên cá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ị cũ hơn (xem phần nói về Hỗ trợ các phiên bản cũ hơn với tiêu đề tùy chọn).

Hình 4. Bố trí có hai bảng với tiêu đề.
1. Tiêu đề được định nghĩa trong một tệp tiêu đề XML.
2. Mỗi nhóm thiết đặt được định nghĩa bởi một {@link android.preference.PreferenceFragment}, được quy định bởi một phần tử {@code <header>} trong tệp tiêu đề .

Hình 5. Thiết bị cầm tay với các tiêu đề thiết đặt. Khi một mục được chọn, {@link android.preference.PreferenceFragment} được liên kết sẽ thay thế tiêu đề.

Tạo tệp tiêu đề

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>} đơn lẻ bên trong một phần tử {@code <preference-headers>} gốc. Ví dụ:

<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header 
        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one" />
    <header 
        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" >
        <!-- key/value pairs can be included as arguments for the fragment. -->
        <extra android:name="someKey" android:value="someHeaderValue" />
    </header>
</preference-headers>

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 android.preference.PreferenceFragment} mà sẽ mở khi người dùng chọn tiêu đề đó.

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 android.os.Bundle}. Phân đoạn có thể truy xuất các tham đối bằng cách gọi {@link android.app.Fragment#getArguments()}. Bạn có thể chuyển các tham đối tới phân đoạn vì nhiều lý 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 android.preference.PreferenceFragment} cho mỗi nhóm và sử dụng tham đối để quy định tệp XML tùy chọn nào mà phân đoạn cần tải.

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 tiêu đề định nghĩa một tham đối {@code <extra>} với khóa {@code "settings"}:

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String settings = getArguments().getString("settings");
        if ("notifications".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_wifi);
        } else if ("sync".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_sync);
        }
    }
}

Hiển thị tiêu đề

Để 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 android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} và gọi {@link android.preference.PreferenceActivity#loadHeadersFromResource loadHeadersFromResource()}. Ví dụ:

public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }
}

Khi người dùng chọn một mục từ danh sách tiêu đề, hệ thống sẽ mở {@link android.preference.PreferenceFragment} kèm theo.

Lưu ý: Khi sử dụng tiêu đề tùy chọn, lớp con {@link android.preference.PreferenceActivity} của bạn không cần triển khai phương pháp {@link android.preference.PreferenceActivity#onCreate onCreate()}, vì tác vụ cần thiết duy nhất cho hoạt động đó là tải tiêu đề.

Hỗ trợ các phiên bản cũ hơn với tiêu đề tùy chọn

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 đề để cung 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 tệp XML tùy chọn bổ sung có sử dụng phần tử cơ bản {@link android.preference.Preference <Preference>} đóng vai trò như mục tiêu đề (để dùng cho các phiên bản Android cũ hơn).

Tuy nhiên, thay vì mở một {@link android.preference.PreferenceScreen} mới, từng phần tử {@link android.preference.Preference <Preference>} sẽ gửi một {@link android.content.Intent} tới {@link android.preference.PreferenceActivity} mà quy định tệp XML tùy chọn cần tải.

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 trở lên ({@code res/xml/preference_headers.xml}):

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header 
        android:fragment="com.example.prefs.SettingsFragmentOne"
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one" />
    <header 
        android:fragment="com.example.prefs.SettingsFragmentTwo"
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" />
</preference-headers>

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 Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <Preference 
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one"  >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_ONE" />
    </Preference>
    <Preference 
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_TWO" />
    </Preference>
</PreferenceScreen>

Vì hỗ trợ dành cho {@code <preference-headers>} đã được thêm trong Android 3.0, hệ thống sẽ gọi {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} trong {@link android.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 tệp tiêu đề "kế thừa" ({@code preference_headers_legacy.xml}), bạn phải kiểm tra phiên bản Android và, nếu phiên bản cũ hơn Android 3.0 ({@link android.os.Build.VERSION_CODES#HONEYCOMB}), hãy gọi {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} để tải tệp tiêu đề kế thừa. Ví dụ:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // Load the legacy preferences headers
        addPreferencesFromResource(R.xml.preference_headers_legacy);
    }
}

// Called only on Honeycomb and later
@Override
public void onBuildHeaders(List<Header> target) {
   loadHeadersFromResource(R.xml.preference_headers, target);
}

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 hoạ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 cá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:

final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
...

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String action = getIntent().getAction();
    if (action != null && action.equals(ACTION_PREFS_ONE)) {
        addPreferencesFromResource(R.xml.preferences);
    }
    ...

    else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // Load the legacy preferences headers
        addPreferencesFromResource(R.xml.preference_headers_legacy);
    }
}

Lưu ý rằng các lệnh gọi liên tiếp đến {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} sẽ xế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 điều kiện với mệnh đề else-if.

Đọc Tùy chọn

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 trong ứng dụng của bạn bằng cách gọi phương pháp tĩnh {@link android.preference.PreferenceManager#getDefaultSharedPreferences PreferenceManager.getDefaultSharedPreferences()}. Điều này sẽ trả về đối tượng {@link android.content.SharedPreferences} chứa tất cả cặp khóa-giá trị liên kết với các đối tượng {@link android.preference.Preference} được sử dụng trong {@link android.preference.PreferenceActivity}.

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 của mình:

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");

Theo dõi thay đổi tùy chọn

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 tù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, hãy triển khai giao diện {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener SharedPreference.OnSharedPreferenceChangeListener} và đăng ký đối tượng theo dõi cho đối tượng {@link android.content.SharedPreferences} bằng cách gọi {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()}.

Giao diện này chỉ có một phương pháp gọi lại, {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()}, 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 hoạt động của mình. Ví dụ:

public class SettingsActivity extends PreferenceActivity
                              implements OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    ...

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
        String key) {
        if (key.equals(KEY_PREF_SYNC_CONN)) {
            Preference connectionPref = findPreference(key);
            // Set summary to be the user-description for the selected value
            connectionPref.setSummary(sharedPreferences.getString(key, ""));
        }
    }
}

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ó sẽ gọi {@link android.preference.PreferenceActivity#findPreference findPreference()} để nhận đối tượng {@link android.preference.Preference} đã bị thay đổi để nó có thể sửa đổi tóm tắt củ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 android.preference.ListPreference} hoặc thiết đặt nhiều lựa chọn khác, bạn nên gọi {@link android.preference.Preference#setSummary setSummary()} khi thiết đặt thay đổi để hiển thị trạng thái hiện tại (chẳng hạn như thiết đặt Ngủ như minh họa trong hình 5).

Lưu ý: Như đã mô tả trong tài liệu Thiết kế Android về Thiết đặt, chúng tôi khuyên bạn nên cập nhật tóm tắt cho {@link android.preference.ListPreference} mỗi khi người dùng thay đổi tùy chọn để mô tả thiết đặt hiện tại.

Để 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ý {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} của mình tương ứng trong {@link android.app.Activity#onResume} và các lệnh gọi lại {@link android.app.Activity#onPause}:

@Override
protected void onResume() {
    super.onResume();
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

Chú ý: Khi bạn gọi {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()}, trình quản lý tùy chọn hiện khô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 mạ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 khuyê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 mà sẽ tồn tại miễn là bạn còn cần đối tượng theo dõi đó.

Ví dụ, trong đoạn mã sau, hàm gọi không giữ tham chiếu tới đố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, và nó sẽ bị lỗi tại một thời điểm không xác định trong tương lai:

prefs.registerOnSharedPreferenceChangeListener(
  // Bad! The listener is subject to garbage collection!
  new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // listener implementation
  }
});

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 đối tượng mà sẽ tồn tại miễn là còn cần đối tượng theo dõi đó:

SharedPreferences.OnSharedPreferenceChangeListener listener =
    new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // listener implementation
  }
};
prefs.registerOnSharedPreferenceChangeListener(listener);

Quản lý Sử dụng Mạng

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 ứ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ể vô 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 củ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 ngườ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.

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 chỉ đượ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 nhữ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 hơ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 lượng dữ liệu mà ứng dụng của bạn sử dụng.

Sau khi bạn đã thêm các tùy chọn cần thiết trong {@link android.preference.PreferenceActivity} củ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 android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} trong tệp bản kê khai của mình. Ví dụ:

<activity android:name="SettingsActivity" ... >
    <intent-filter>
       <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

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 củ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 Thiết đặt của hệ thống, sẽ có một nút Xem thiết đặt ứng dụng khởi chạy {@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 dùng.

Xây dựng một Thiết đặt Tùy chỉnh

Khuôn khổ Android bao gồm nhiều lớp con {@link android.preference.Preference} mà cho phép bạn xây dựng một UI cho một vài loại thiết đặt khác nhau. Tuy 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 bộ 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 lớp {@link android.preference.Preference} hoặc một trong các lớp con khác.

Khi bạn mở rộng lớp {@link android.preference.Preference}, có một vài điều quan trọng mà bạn cần làm:

Các phần sau mô tả cách hoàn thành từng tác vụ này.

Quy định một giao diện người dùng

Nếu bạn trực tiếp mở rộng lớp {@link android.preference.Preference}, bạn cần triển khai {@link android.preference.Preference#onClick()} để định nghĩa hành động xảy ra khi người dùng chọ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} để hiể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 android.preference.DialogPreference}, bạn phải gọi {@link android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} trong khi đang ở trong hàm dựng lớp để quy định bố trí cho hộp thoại.

Ví dụ, sau đây là hàm dựng cho một {@link android.preference.DialogPreference} tùy chỉnh mà khai báo bố trí và quy định văn bản cho các nút hộp thoại tích cực và tiêu cực mặc định:

public class NumberPickerPreference extends DialogPreference {
    public NumberPickerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        
        setDialogLayoutResource(R.layout.numberpicker_dialog);
        setPositiveButtonText(android.R.string.ok);
        setNegativeButtonText(android.R.string.cancel);
        
        setDialogIcon(null);
    }
    ...
}

Lưu giá trị của thiết đặt

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 android.preference.Preference}, {@code persist*()}, chẳng hạn như {@link android.preference.Preference#persistInt persistInt()} nếu giá trị của thiết đặt là một số nguyên hoặc {@link android.preference.Preference#persistBoolean persistBoolean()} để lưu một boolean.

Lưu ý: Mỗi {@link android.preference.Preference} chỉ có thể lưu một kiể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 {@link android.preference.Preference} tùy chỉnh của mình.

Thời điểm bạn chọn duy trì thiết đặt có thể phụ thuộc vào lớp {@link android.preference.Preference} nào mà bạn mở rộng. Nếu mở rộng {@link android.preference.DialogPreference}, khi đó bạn nên duy trì giá trị đó chỉ khi hộp thoại đóng lại do kết quả tích cực (người dùng chọn nút "OK").

Khi {@link android.preference.DialogPreference} đóng lại, hệ thống sẽ gọi phương pháp {@link android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Phương pháp bao gồm một tham đố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à true, 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í dụ:

@Override
protected void onDialogClosed(boolean positiveResult) {
    // When the user selects "OK", persist the new value
    if (positiveResult) {
        persistInt(mNewValue);
    }
}

Trong ví dụ này, mNewValue là một thành viên lớp lưu giữ giá trị hiệ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 tệp {@link android.content.SharedPreferences} (tự động sử dụng khóa mà được quy định trong tệp XML cho {@link android.preference.Preference} này).

Khởi tạo giá trị hiện tại

Khi hệ thống thêm {@link android.preference.Preference} của bạn vào màn hình, nó gọi {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} để thông báo vớ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 cho bạn giá trị mặc định.

Phương pháp {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} chuyển một boolean, restorePersistedValue, để cho biết liệu giá trị đã được duy trì cho thiết đặt hay không. Nếu nó là true, khi đó bạn nên truy xuất giá trị được duy trì bằng cách gọi một trong các phương pháp của lớp {@link android.preference.Preference}, {@code getPersisted*()}, chẳng hạn như {@link android.preference.Preference#getPersistedInt getPersistedInt()} đối với một giá trị số nguyên. Bạn sẽ thườ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 giá trị đã lưu trước đó.

Nếu restorePersistedValuefalse, vậy bạn nên sử dụng giá trị mặc định được chuyển trong tham đối thứ hai.

@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
    if (restorePersistedValue) {
        // Restore existing state
        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
    } else {
        // Set default state from the XML attribute
        mCurrentValue = (Integer) defaultValue;
        persistInt(mCurrentValue);
    }
}

Mỗi phương pháp {@code getPersisted*()} sẽ lấy một tham đối quy định giá 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 ví 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 android.preference.Preference#getPersistedInt getPersistedInt()} không thể trả về một giá trị được duy trì.

Chú ý: Bạn không thể sử dụng defaultValue làm giá trị mặc định trong phương pháp {@code getPersisted*()}, bởi giá trị của nó luôn rỗng khi restorePersistedValuetrue.

Cung cấp một giá trị mặc định

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 (với thuộc tính {@code android:defaultValue}), khi đó hệ thống sẽ gọi {@link android.preference.Preference#onGetDefaultValue onGetDefaultValue()} khi nó khởi tạo đối tượng để truy xuất giá trị. Bạn phải triển khai phương pháp này để hệ thống lưu giá trị mặc định trong {@link android.content.SharedPreferences}. Ví dụ:

@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
    return a.getInteger(index, DEFAULT_VALUE);
}

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 của {@code android:defaultValue} mà bạn phải truy xuất. Lý do bạn phải triển khai phươ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 mộ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.

Lưu và khôi phục trạng thái của Tùy chọn

Giống như {@link android.view.View} trong một bố trí, lớp con {@link android.preference.Preference} củ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 đượ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 trạ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 phương pháp gọi lại vòng đời {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} và {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.

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 giao 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 như một điểm bắt đầu để định nghĩa đối tượng trạng thái của bạn: lớp {@link android.preference.Preference.BaseSavedState}.

Để đị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ó hãy mở rộng lớp {@link android.preference.Preference.BaseSavedState}. Bạn cần khống chế chỉ một vài phương pháp và định nghĩa đối tượng {@link android.preference.Preference.BaseSavedState#CREATOR} .

Đố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 xử lý {@code value} nếu lớp con {@link android.preference.Preference} của bạn lưu một kiểu dữ liệu khác số nguyên.

private static class SavedState extends BaseSavedState {
    // Member that holds the setting's value
    // Change this data type to match the type saved by your Preference
    int value;

    public SavedState(Parcelable superState) {
        super(superState);
    }

    public SavedState(Parcel source) {
        super(source);
        // Get the current preference's value
        value = source.readInt();  // Change this to read the appropriate data type
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        // Write the preference's value
        dest.writeInt(value);  // Change this to write the appropriate data type
    }

    // Standard creator object using an instance of this class
    public static final Parcelable.Creator<SavedState> CREATOR =
            new Parcelable.Creator<SavedState>() {

        public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
        }

        public SavedState[] newArray(int size) {
            return new SavedState[size];
        }
    };
}

Với triển khai {@link android.preference.Preference.BaseSavedState} bên trên được thêm và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 đó bạn cần triển khai các phương pháp {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} và {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} cho lớp con {@link android.preference.Preference} của mình.

Ví dụ:

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    // Check whether this Preference is persistent (continually saved)
    if (isPersistent()) {
        // No need to save instance state since it's persistent,
        // use superclass state
        return superState;
    }

    // Create instance of custom BaseSavedState
    final SavedState myState = new SavedState(superState);
    // Set the state's value with the class member that holds current
    // setting value
    myState.value = mNewValue;
    return myState;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    // Check whether we saved the state in onSaveInstanceState
    if (state == null || !state.getClass().equals(SavedState.class)) {
        // Didn't save the state, so call superclass
        super.onRestoreInstanceState(state);
        return;
    }

    // Cast state to custom BaseSavedState and pass to superclass
    SavedState myState = (SavedState) state;
    super.onRestoreInstanceState(myState.getSuperState());
    
    // Set this Preference's widget to reflect the restored state
    mNumberPicker.setValue(myState.value);
}