page.title=Pengaturan page.tags=preference,preferenceactivity,preferencefragment @jd:body
Aplikasi sering kali menyertakan pengaturan yang memungkinkan pengguna memodifikasi fitur dan perilaku aplikasi. Misalnya, beberapa aplikasi memungkinkan pengguna untuk menetapkan apakah pemberitahuan diaktifkan atau menetapkan seberapa sering aplikasi menyinkronkan data dengan cloud.
Jika ingin menyediakan pengaturan untuk aplikasi, Anda harus menggunakan API Android {@link android.preference.Preference} untuk membangun antarmuka yang konsisten dengan pengalaman pengguna di aplikasi Android yang lain (termasuk pengaturan sistem). Dokumen ini menjelaskan cara membangun pengaturan aplikasi Anda menggunakan API {@link android.preference.Preference}.
Desain Pengaturan
Untuk informasi tentang cara mendesain pengaturan Anda, bacalah panduan desain Pengaturan.
Sebagai ganti menggunakan objek {@link android.view.View} untuk membangun antarmuka pengguna, pengaturan dibangun menggunakan berbagai subkelas dari kelas {@link android.preference.Preference} yang Anda deklarasikan dalam file XML.
Objek {@link android.preference.Preference} adalah blok pembangun untuk pengaturan tunggal. Setiap {@link android.preference.Preference} muncul sebagai item dalam daftar dan menyediakan UI yang sesuai bagi pengguna untuk memodifikasi pengaturan. Misalnya, {@link android.preference.CheckBoxPreference} membuat item daftar yang menampilkan kotak cek, dan {@link android.preference.ListPreference} membuat item yang membuka dialog berisi daftar pilihan.
Setiap {@link android.preference.Preference} yang Anda tambahkan memiliki pasangan nilai-kunci yang sesuai yang digunakan sistem untuk menyimpan pengaturan dalam file {@link android.content.SharedPreferences} default untuk pengaturan aplikasi Anda. Bila pengguna mengubah pengaturan, sistem akan memperbarui nilai yang bersangkutan dalam file {@link android.content.SharedPreferences} untuk Anda. Satu-satunya saat di mana Anda harus berinteraksi langsung dengan file {@link android.content.SharedPreferences} yang terkait adalah bila Anda perlu membaca nilai untuk menentukan perilaku aplikasi berdasarkan pengaturan pengguna.
Nilai yang tersimpan di {@link android.content.SharedPreferences} untuk setiap pengaturan bisa berupa tipe data berikut:
Oleh karena UI pengaturan aplikasi Anda dibangun menggunakan objek {@link android.preference.Preference} sebagai ganti objek {@link android.view.View}, Anda perlu menggunakan {@link android.app.Activity} khusus atau subkelas {@link android.app.Fragment} untuk menampilkan pengaturan daftar:
Cara mengatur {@link android.preference.PreferenceActivity} Anda dan instance {@link android.preference.PreferenceFragment} dibahas di bagian tentang Membuat Aktivitas Preferensi dan Menggunakan Fragmen Preferensi.
Setiap pengaturan untuk aplikasi Anda diwakili oleh subkelas khusus dari kelas {@link android.preference.Preference}. Setiap subkelas menyertakan seperangkat properti utama yang memungkinkan Anda untuk menetapkan berbagai hal seperti judul pengaturan dan nilai default. Setiap subkelas juga menyediakan antarmuka pengguna dan properti khusus miliknya sendiri. Misalnya, gambar 1 menampilkan cuplikan layar dari pengaturan aplikasi Messaging. Setiap item daftar dalam layar pengaturan didukung oleh objek {@link android.preference.Preference} berbeda.
Beberapa preferensi yang paling umum adalah:
true
jika diberi tanda cek).Lihat kelas {@link android.preference.Preference} untuk mengetahui daftar subkelas lain dan propertinya.
Tentu saja, kelas bawaan tidak mengakomodasi setiap kebutuhan dan aplikasi Anda mungkin memerlukan sesuatu yang lebih khusus. Misalnya, platform saat ini tidak menyediakan kelas {@link android.preference.Preference} untuk mengambil nomor atau tanggal. Anda mungkin perlu mendefinisikan subkelas {@link android.preference.Preference} sendiri. Untuk bantuan melakukannya, lihat bagian tentang Membangun Preferensi Custom.
Meskipun bisa membuat instance objek {@link android.preference.Preference} baru saat runtime, Anda harus mendefinisikan daftar pengaturan dalam XML dengan hierarki objek {@link android.preference.Preference}. Menggunakan file XML untuk mendefinisikan sekumpulan pengaturan lebih disukai karena file menyediakan struktur yang mudah dibaca dan diperbarui. Selain itu, pengaturan aplikasi Anda umumnya telah ditetapkan sebelumnya, meskipun Anda masih bisa memodifikasi kumpulan tersebut saat runtime.
Setiap subkelas {@link android.preference.Preference} bisa dideklarasikan dengan elemen XML yang cocok dengan nama kelas, seperti {@code <CheckBoxPreference>}.
Anda harus menyimpan file XML dalam direktori {@code res/xml/}. Meskipun bisa memberi nama file sesuka Anda, biasanya file diberi nama {@code preferences.xml}. Biasanya Anda hanya memerlukan satu file, karena cabang di hierarki (yang membuka daftar pengaturanny sendiri) dideklarasikan menggunakan instance tersarang {@link android.preference.PreferenceScreen}.
Catatan: Jika ingin membuat layout multipanel untuk pengaturan, Anda memerlukan file XML terpisah untuk setiap fragmen.
Simpul akar untuk file XML harus merupakan elemen {@link android.preference.PreferenceScreen <PreferenceScreen>}. Dalam elemen inilah tempat Anda menambahkan setiap {@link android.preference.Preference}. Setiap anak yang Anda tambahkan dalam elemen {@link android.preference.PreferenceScreen <PreferenceScreen>} akan tampak sebagai item tunggal dalam daftar pengaturan.
Misalnya:
<?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>
Dalam contoh ini, terdapat {@link android.preference.CheckBoxPreference} dan {@link android.preference.ListPreference}. Kedua item tersebut menyertakan tiga atribut berikut:
Instance satu-satunya di mana atribut ini tidak diperlukan adalah bila preferensi berupa {@link android.preference.PreferenceCategory} atau {@link android.preference.PreferenceScreen}, atau preferensi menetapkan {@link android.content.Intent} untuk dipanggil (dengan elemen {@code <intent>}) atau {@link android.app.Fragment} untuk ditampilkan (dengan atribut {@code android:fragment}).
Untuk informasi tentang semua atribut lain yang didukung, lihat dokumentasi {@link android.preference.Preference} (dan subkelas masing-masing).
Bila daftar pengaturan Anda melebihi sekitar 10 item, Anda mungkin perlu menambahkan judul untuk mendefinisikan grup pengaturan atau menampilkan grup tersebut di layar terpisah. Opsi ini dijelaskan di bagian berikut.
Jika Anda menampilkan daftar 10 pengaturan atau lebih, pengguna mungkin akan kesulitan dalam memindai, memahami dan memprosesnya. Anda bisa mengatasinya dengan membagi sebagian atau semua pengaturan ke dalam beberapa grup, yang secara efektif akan mengubah satu daftar panjang menjadi beberapa daftar yang lebih pendek. Suatu grup pengaturan terkait bisa ditampilkan dalam salah satu dari dua cara:
Anda bisa menggunakan salah satu atau keduanya untuk mengelola pengaturan aplikasi Anda. Saat memutuskan mana yang akan digunakan dan cara membagi pengaturan, Anda harus mengikuti pedoman dalam Panduan Pengaturan Desain Android.
Jika ingin menyediakan divider dengan heading di antara grup pengaturan (seperti yang ditampilkan dalam gambar 2), tempatkan setiap grup objek {@link android.preference.Preference} di dalam {@link android.preference.PreferenceCategory}.
Misalnya:
<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>
Jika ingin menempatkan grup pengaturan ke dalam sublayar (seperti yang ditampilkan dalam gambar 3), tempatkan grup objek {@link android.preference.Preference} di dalam {@link android.preference.PreferenceScreen}.
Misalnya:
<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>
Dalam beberapa kasus, Anda mungkin ingin item preferensi untuk membuka beberapa aktivitas sebagai ganti layar pengaturan, seperti browser web untuk melihat halaman web. Untuk memanggil {@link android.content.Intent} saat pengguna memilih item preferensi, tambahkan elemen {@code <intent>} sebagai anak dari elemen {@code <Preference>} yang bersangkutan.
Misalnya, berikut ini cara menggunakan item preferensi untuk membuka halaman web:
<Preference android:title="@string/prefs_web_page" > <intent android:action="android.intent.action.VIEW" android:data="http://www.example.com" /> </Preference>
Anda bisa membuat intent implisit maupun eksplisit menggunakan atribut berikut:
Untuk menampilkan pengaturan Anda dalam suatu aktivitas, perluas kelas {@link android.preference.PreferenceActivity}. Ini adalah ekstensi dari kelas {@link android.app.Activity} biasa yang menampilkan daftar pengaturan berdasarkan hierarki objek {@link android.preference.Preference}. {@link android.preference.PreferenceActivity} secara otomatis mempertahankan pengaturan yang dikaitkan dengan setiap {@link android.preference.Preference} bila pengguna membuat perubahan.
Catatan: Jika Anda mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, sebaiknya gunakan {@link android.preference.PreferenceFragment}. Pindah ke bagian berikutnya tentang Menggunakan Fragmen Preferensi.
Hal paling penting untuk diingat adalah jangan memuat layout tampilan selama callback {@link android.preference.PreferenceActivity#onCreate onCreate()}. Sebagai gantinya, panggil {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk menambahkan preferensi yang telah Anda deklarasikan dalam file XML ke aktivitas. Misalnya, berikut ini adalah kode minimum polos yang diperlukan untuk {@link android.preference.PreferenceActivity} fungsional:
public class SettingsActivity extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } }
Ini sebenarnya kode yang cukup untuk beberapa aplikasi, karena segera setelah pengguna memodifikasi preferensi, sistem akan menyimpan perubahan tersebut ke file {@link android.content.SharedPreferences} default yang bisa dibaca oleh komponen aplikasi Anda lainnya bila Anda perlu memeriksa pengaturan pengguna. Akan tetapi, banyak aplikasi, yang memerlukan kode lebih sedikit untuk mendengarkan perubahan yang terjadi pada preferensi. Untuk informasi tentang mendengarkan perubahan di file {@link android.content.SharedPreferences}, lihat bagian tentang Preferensi Membaca.
Jika Anda mengembangkan Android 3.0 (API level 11) dan yang lebih tinggi, Anda harus menggunakan {@link android.preference.PreferenceFragment} untuk menampilkan daftar objek {@link android.preference.Preference} Anda. Anda bisa menambahkan {@link android.preference.PreferenceFragment} ke aktivitas apa pun,—Anda tidak perlu menggunakan {@link android.preference.PreferenceActivity}.
Fragmen menyediakan arsitektur yang lebih fleksibel untuk aplikasi Anda, dibandingkan hanya menggunakan aktivitas, apa pun jenis aktivitas yang Anda bangun. Dengan sendirinya, kami menyarankan Anda menggunakan {@link android.preference.PreferenceFragment} untuk mengontrol tampilan pengaturan Anda sebagai ganti {@link android.preference.PreferenceActivity} bila memungkinkan.
Implementasi {@link android.preference.PreferenceFragment} Anda bisa semudah mendefinisikan metode {@link android.preference.PreferenceFragment#onCreate onCreate()} untuk memuat file preferensi dengan {@link android.preference.PreferenceFragment#addPreferencesFromResource addPreferencesFromResource()}. Misalnya:
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); } ... }
Anda nanti bisa menambahkan fragmen ini ke {@link android.app.Activity} seperti yang Anda lakukan untuk {@link android.app.Fragment} lainnya. Misalnya:
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(); } }
Catatan: {@link android.preference.PreferenceFragment} tidak memiliki objek {@link android.content.Context} sendiri. Jika memerlukan objek {@link android.content.Context} , Anda bisa memanggil {@link android.app.Fragment#getActivity()}. Akan tetapi, berhati-hatilah untuk memanggil {@link android.app.Fragment#getActivity()} hanya bila fragmen telah dikaitkan dengan aktivitas. Bila fragmen belum dikaitkan, atau terlepas saat akhir daur hidupnya, {@link android.app.Fragment#getActivity()} akan mengembalikan nol.
Preferensi yang Anda buat mungkin mendefinisikan beberapa perilaku penting untuk aplikasi, jadi Anda perlu menginisialisasi file {@link android.content.SharedPreferences} yang terkait dengan nilai default untuk setiap {@link android.preference.Preference} bila pengguna menggunakan aplikasi Anda untuk pertama kali.
Hal pertama yang harus Anda lakukan adalah menetapkan nilai default untuk setiap objek {@link android.preference.Preference} di file XML Anda menggunakan atribut {@code android:defaultValue}. Nilainya bisa berupa tipe data apa saja yang sesuai untuk objek {@link android.preference.Preference} bersangkutan. Misalnya:
<!-- default value is a boolean --> <CheckBoxPreference android:defaultValue="true" ... /> <!-- default value is a string --> <ListPreference android:defaultValue="@string/pref_syncConnectionTypes_default" ... />
Kemudian, dari metode {@link android.app.Activity#onCreate onCreate()} dalam aktivitas utama aplikasi Anda—dan dalam aktivitas lainnya yang digunakan pengguna untuk masuk ke aplikasi Anda untuk pertama kali —panggil {@link android.preference.PreferenceManager#setDefaultValues setDefaultValues()}:
PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
Memanggil ini selama {@link android.app.Activity#onCreate onCreate()} akan memastikan aplikasi Anda diinisialisasi dengan pengaturan default, yang mungkin perlu dibaca oleh aplikasi Anda untuk menentukan beberapa perilaku (seperti apakah akan mengunduh data pada jaringan seluler).
Metode ini membutuhkan tiga argumen:
Bila false
, sistem akan mengatur nilai default hanya jika metode ini belum pernah
dipanggil sebelumnya (atau {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
dalam file preferensi berbagi nilai default salah).
Selama Anda mengatur argumen ketiga ke false
, Anda bisa dengan aman memanggil metode ini
setiap kali aktivitas Anda memulai tanpa mengesampingkan preferensi tersimpan pengguna dengan mengatur ulang preferensi tersebut ke
default. Akan tetapi, jika mengatur ke true
, Anda akan mengesampingkan nilai
sebelumnya dengan default.
Dalam kasus yang jarang terjadi, Anda mungkin perlu mendesain pengaturan agar layar pertama hanya menampilkan daftar sublayar (seperti dalam aplikasi Setting pada sistem, seperti yang ditampilkan dalam gambar 4 dan 5). Bila mengembangkan desain seperti itu untuk Android 3.0 dan yang lebih tinggi, Anda harus menggunakan fitur "header" yang baru di Android 3.0, sebagai ganti membangun sublayar dengan elemen {@link android.preference.PreferenceScreen} tersarang.
Untuk membangun pengaturan dengan header, Anda perlu:
Manfaat besar dalam menggunakan desain ini adalah karena {@link android.preference.PreferenceActivity} secara otomatis akan menampilkan layout dua panel yang ditampilkan dalam gambar 4 bila dijalankan pada layar besar.
Bahkan jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda bisa membangun aplikasi untuk menggunakan {@link android.preference.PreferenceFragment} bagi presentasi dua panel pada perangkat yang lebih baru sementara tetap mendukung hierarki multilayar biasa pada perangkat yang lebih lama (lihat bagian tentang Mendukung versi yang lebih lama dengan header preferensi).
Setiap grup pengaturan dalam daftar header Anda akan ditetapkan oleh elemen {@code <header>} tunggal dalam elemen {@code <preference-headers>} akar. Misalnya:
<?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>
Dengan atribut {@code android:fragment}, setiap header mendeklarasikan instance {@link android.preference.PreferenceFragment} yang harus terbuka saat pengguna memilih header.
Elemen {@code <extras>} memungkinkan Anda meneruskan pasangan nilai-kunci ke fragmen di {@link android.os.Bundle}. Fragmen bisa mengambil argumen dengan memanggil {@link android.app.Fragment#getArguments()}. Anda bisa meneruskan argumen ke fragmen dengan berbagai alasan, namun satu alasan yang baik adalah untuk menggunakan kembali subkelas yang sama dari {@link android.preference.PreferenceFragment} untuk setiap grup dan menggunakan argumen untuk menetapkan file XML preferensi mana yang harus dimuat fragmen.
Misalnya, ada fragmen yang bisa digunakan ulang untuk berbagai grup pengaturan, bila setiap header mendefinisikan argumen {@code <extra>} dengan kunci {@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); } } }
Untuk menampilkan header preferensi, Anda harus mengimplementasikan metode callback {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} dan memanggil {@link android.preference.PreferenceActivity#loadHeadersFromResource loadHeadersFromResource()}. Misalnya:
public class SettingsActivity extends PreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.preference_headers, target); } }
Bila pengguna memilih item dari daftar header, sistem akan membuka {@link android.preference.PreferenceFragment} terkait.
Catatan: Saat menggunakan header preferensi, subkelas {@link android.preference.PreferenceActivity} Anda tidak perlu mengimplementasikan metode {@link android.preference.PreferenceActivity#onCreate onCreate()}, karena tugas yang diperlukan untuk aktivitas hanyalah memuat header.
Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda tetap bisa menggunakan header untuk menyediakan layout dua panel saat berjalan pada Android 3.0 dan yang lebih tinggi. Anda hanya perlu membuat file XML preferensi tambahan yang menggunakan elemen {@link android.preference.Preference <Preference>} dasar yang berperilaku seperti item header (untuk digunakan oleh Android versi yang lebih lama).
Akan tetapi, sebagai ganti membuka {@link android.preference.PreferenceScreen} baru, setiap elemen {@link android.preference.Preference <Preference>} mengirimkan {@link android.content.Intent} ke {@link android.preference.PreferenceActivity} yang menetapkan file XML preferensi mana yang akan dimuat.
Misalnya, ini adalah file XML untuk header preferensi yang menggunakan Android 3.0 dan yang lebih tinggi ({@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>
Dan ini adalah file preferensi yang menyediakan header yang sama untuk versi yang lebih lama dari 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>
Karena dukungan untuk {@code <preference-headers>} telah ditambahkan di Android 3.0, sistem akan memanggil {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} di {@link android.preference.PreferenceActivity} hanya saat berjalan pada Android 3.0 atau yang lebih tinggi. Untuk memuat file header "lama" ({@code preference_headers_legacy.xml}), Anda harus memeriksa versi Android dan, jika versi tersebut lebih lama dari Android 3.0 ({@link android.os.Build.VERSION_CODES#HONEYCOMB}), panggil {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk memuat file header lama. Misalnya:
@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); }
Satu-satunya hal yang perlu dilakukan adalah menangani {@link android.content.Intent} yang diteruskan ke aktivitas untuk mengidentifikasi file preferensi yang akan dimuat. Jadi ambillah tindakan intent dan bandingkan dengan string tindakan yang diketahui yang telah Anda gunakan dalam tag {@code <intent>} XML preferensi:
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); } }
Ketahuilah bahwa panggilan berturut-turut ke {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} akan menumpuk semua preferensi ke dalam satu daftar, jadi pastikan bahwa ini hanya dipanggil sekali dengan mengikatkan syarat ke pernyataan else-if.
Secara default, semua preferensi aplikasi Anda disimpan ke file yang bisa diakses dari mana saja di dalam aplikasi dengan memanggil metode statis {@link android.preference.PreferenceManager#getDefaultSharedPreferences PreferenceManager.getDefaultSharedPreferences()}. Ini akan mengembalikan objek {@link android.content.SharedPreferences} berisi semua pasangan nilai-kunci yang terkait dengan objek {@link android.preference.Preference} yang digunakan di {@link android.preference.PreferenceActivity} Anda.
Misalnya, inilah cara membaca salah satu nilai preferensi dari aktivitas lain dalam aplikasi Anda:
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
Ada beberapa alasan yang membuat Anda perlu mendapatkan pemberitahuan segera setelah pengguna mengubah salah satu preferensi. Untuk menerima callback saat perubahan terjadi pada salah satu preferensi, implementasikan antarmuka {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener SharedPreference.OnSharedPreferenceChangeListener} dan daftarkan listener untuk objek {@link android.content.SharedPreferences} dengan memanggil {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()}.
Antarmuka hanya memiliki satu metode callback, {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()}, dan mungkin lebih mudah mengimplementasikan antarmuka sebagai bagian dari aktivitas Anda. Misalnya:
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, "")); } } }
Dalam contoh ini, metode akan memeriksa apakah pengaturan yang diubah adalah untuk kunci preferensi yang diketahui. Ini akan memanggil {@link android.preference.PreferenceActivity#findPreference findPreference()} untuk mendapatkan objek {@link android.preference.Preference} yang diubah agar bisa memodifikasi rangkuman item menjadi keterangan pada pilihan pengguna. Ini berarti, bila pengaturan adalah {@link android.preference.ListPreference} atau pengaturan multipilihan, Anda harus memanggil {@link android.preference.Preference#setSummary setSummary()} bila pengaturan berubah ke tampilkan status saat ini (seperti pengaturan Sleep yang ditampilkan dalam gambar 5).
Catatan: Seperti dijelaskan dalam dokumen Desain Android tentang Pengaturan, kami merekomendasikan Anda untuk memperbarui rangkuman {@link android.preference.ListPreference} setiap kali pengguna mengubah preferensi untuk menjelaskan pengaturan saat ini.
Untuk manajemen daur hidup yang baik di aktivitas, kami merekomendasikan Anda untuk mendaftarkan dan mencabut pendaftaran {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} selama callback {@link android.app.Activity#onResume} dan {@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); }
Perhatian: Bila Anda memanggil {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()}, pengelola preferensi saat ini tidak akan menyimpan referensi kuat ke listener. Anda harus menyimpan referensi kuat bagi listener, atau referensi akan rentan terhadap pengumpulan sampah. Kami merekomendasikan Anda untuk mempertahankan referensi bagi listener dalam data instance objek yang akan ada selama Anda memerlukan listener tersebut.
Misalnya, dalam kode berikut, caller tidak menyimpan referensi ke listener. Akibatnya, listener akan dikenakan pengumpulan sampah, dan suatu saat nanti akan gagal:
prefs.registerOnSharedPreferenceChangeListener( // Bad! The listener is subject to garbage collection! new SharedPreferences.OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { // listener implementation } });
Sebagai gantinya, simpan referensi ke listener dalam bidang data instance objek yang akan ada selama listener dibutuhkan:
SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { // listener implementation } }; prefs.registerOnSharedPreferenceChangeListener(listener);
Mulai Android 4.0, aplikasi Settings untuk sistem memungkinkan pengguna melihat seberapa besar data jaringan yang digunakan aplikasi mereka saat berada di latar depan dan latar belakang. Kemudian pengguna bisa menonaktifkan penggunaan data latar belakang untuk aplikasi individual. Agar pengguna tidak menonaktifkan akses aplikasi ke data dari latar belakang, Anda harus menggunakan koneksi data secara efisien dan mengizinkan pengguna untuk menyaring penggunaan data aplikasi melalui pengaturan aplikasi Anda.
Misalnya, Anda bisa mengizinkan pengguna untuk mengontrol seberapa sering aplikasi menyinkronkan data, apakah aplikasi hanya melakukan pengunggahan/pengunduhan bila ada Wi-Fi, apakah aplikasi menggunakan data saat roaming, dll. Dengan tersedianya kontrol ini bagi pengguna, mereka kemungkinan besar tidak akan menonaktifkan akses aplikasi ke data saat mendekati batas yang mereka tetapkan dalam Settings pada sistem, karena mereka bisa mengontrol secara tepat seberapa besar data yang digunakan aplikasi Anda.
Setelah menambahkan preferensi yang diperlukan dalam {@link android.preference.PreferenceActivity} Anda untuk mengontrol kebiasaan data aplikasi, Anda harus menambahkan filter intent untuk {@link android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} dalam file manifes Anda. Misalnya:
<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>
Filter intent ini menunjukkan pada sistem bahwa ini adalah aktivitas yang mengontrol penggunaan data aplikasi Anda. Jadi, saat pengguna memeriksa seberapa banyak data yang digunakan oleh aplikasi dari aplikasi Settings pada sistem, tombol View application settings akan tersedia dan menjalankan {@link android.preference.PreferenceActivity} sehingga pengguna bisa menyaring seberapa besar data yang digunakan aplikasi Anda.
Kerangka kerja Android menyertakan berbagai subkelas {@link android.preference.Preference} yang memungkinkan Anda membangun UI untuk beberapa macam tipe pengaturan. Akan tetapi, Anda mungkin menemukan pengaturan yang diperlukan bila tidak ada solusi bawaan, seperti picker nomor atau picker tanggal. Dalam hal demikian, Anda akan perlu membuat preferensi custom dengan memperluas kelas {@link android.preference.Preference} atau salah satu subkelas lainnya.
Bila memperluas kelas {@link android.preference.Preference}, ada beberapa hal penting yang perlu Anda lakukan:
Bagian berikut menjelaskan cara melakukan setiap tugas ini.
Jika secara langsung memperluas kelas {@link android.preference.Preference}, Anda perlu mengimplementasikan {@link android.preference.Preference#onClick()} untuk mendefinisikan tindakan yang terjadi bila pengguna memilih item tersebut. Akan tetapi, sebagian besar pengaturan custom memperluas {@link android.preference.DialogPreference} untuk menampilkan dialog, sehingga menyederhanakan prosedur. Bila memperluas {@link android.preference.DialogPreference}, Anda harus memanggil {@link android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} selama di konstruktor kelas untuk menetapkan layout dialog.
Misalnya, beri ini konstruktor untuk {@link android.preference.DialogPreference} custom yang mendeklarasikan layout dan menetapkan teks untuk tombol dialog negatif dan positif default:
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); } ... }
Anda bisa menyimpan nilai pengaturan kapan saja dengan memanggil salah satu metode {@code persist*()} kelas {@link android.preference.Preference}, seperti {@link android.preference.Preference#persistInt persistInt()} jika nilai pengaturan adalah integer atau {@link android.preference.Preference#persistBoolean persistBoolean()} untuk menyimpan boolean.
Catatan: Setiap {@link android.preference.Preference} hanya bisa menyimpan satu tipe data, jadi Anda harus menggunakan metode {@code persist*()} yang tepat untuk tipe data yang digunakan oleh {@link android.preference.Preference} custom Anda.
Bila Anda memilih untuk mempertahankannya, pengaturan bisa bergantung pada kelas {@link android.preference.Preference} yang Anda perluas. Jika Anda memperluas {@link android.preference.DialogPreference}, maka Anda harus mempertahankan nilai hanya jika dialog tertutup karena hasil positif (pengguna memilih tombol "OK").
Bila {@link android.preference.DialogPreference} tertutup, sistem akan memanggil metode {@link
android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Metode mencakup argumen
boolean yang menetapkan apakah hasil pengguna "positif"—jika nilainya
true
, maka pengguna memilih tombol positif dan Anda harus menyimpan nilai baru. Misalnya:
@Override protected void onDialogClosed(boolean positiveResult) { // When the user selects "OK", persist the new value if (positiveResult) { persistInt(mNewValue); } }
Dalam contoh ini, mNewValue
adalah anggota kelas yang menampung nilai
pengaturan saat ini. Memanggil {@link android.preference.Preference#persistInt persistInt()} akan menyimpan nilai
ke file {@link android.content.SharedPreferences} (secara otomatis menggunakan kunci yang
ditetapkan dalam file XML untuk {@link android.preference.Preference} ini).
Bila sistem menambahkan {@link android.preference.Preference} Anda ke layar, ia akan memanggil {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} untuk memberi tahu Anda apakah pengaturan memiliki nilai yang dipertahankan. Jika tidak ada nilai yang dipertahankan, panggilan ini akan menyediakan nilai default bagi Anda.
Metode {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} akan meneruskan
boolean, restorePersistedValue
, untuk menunjukkan apakah nilai dipertahankan
untuk pengaturan. Jika true
, maka Anda harus mengambil nilai yang dipertahankan dengan memanggil
salah satu metode {@code getPersisted*()} kelas {@link
android.preference.Preference}, seperti {@link
android.preference.Preference#getPersistedInt getPersistedInt()} untuk nilai integer. Anda biasanya
perlu mengambil nilai yang dipertahankan agar bisa memperbarui UI dengan benar untuk merefleksikan
nilai yang tersimpan sebelumnya.
Jika restorePersistedValue
adalah false
, maka Anda
harus menggunakan nilai default yang diteruskan dalam argumen kedua.
@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); } }
Setiap metode {@code getPersisted*()} memerlukan argumen yang menetapkan nilai default untuk digunakan jika tidak ada nilai yang dipertahankan atau kunci tidak ada. Dalam contoh di atas, konstanta lokal yang digunakan untuk menetapkan nilai default dalam kasus {@link android.preference.Preference#getPersistedInt getPersistedInt()} tidak bisa mengembalikan nilai yang dipertahankan.
Perhatian: Anda tidak bisa menggunakan
defaultValue
sebagai nilai default dalam metode {@code getPersisted*()}, karena
nilainya selalu nol bila restorePersistedValue
adalah true
.
Jika instance kelas {@link android.preference.Preference} Anda menetapkan nilai default (dengan atribut {@code android:defaultValue}), maka sistem akan memanggil {@link android.preference.Preference#onGetDefaultValue onGetDefaultValue()} bila membuat instance objek untuk mengambil nilai. Anda harus mengimplementasikan metode ini agar sistem bisa menyimpan nilai default dalam {@link android.content.SharedPreferences}. Misalnya:
@Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getInteger(index, DEFAULT_VALUE); }
Argumen metode menyediakan semua hal yang Anda perlukan: larik atribut dan posisi indeks dari {@code android:defaultValue}, yang harus Anda ambil. Alasan Anda harus mengimplementasikan metode ini untuk mengekstrak nilai default dari atribut adalah karena Anda harus menetapkan nilai default lokal untuk atribut jika nilai tidak didefinisikan.
Seperti halnya {@link android.view.View} di layout, subkelas {@link android.preference.Preference} Anda bertanggung jawab menyimpan dan memulihkan statusnya jika aktivitas atau fragmen di-restart (seperti saat pengguna memutar layar). Untuk menyimpan dan memulihkan status kelas {@link android.preference.Preference} dengan benar, Anda harus mengimplementasikan metode callback daur hidup {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} dan {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.
Status {@link android.preference.Preference} Anda didefinisikan oleh objek yang mengimplementasikan antarmuka {@link android.os.Parcelable}. Kerangka kerja Android menyediakan objek seperti itu untuk Anda gunakan sebagai titik mulai untuk mendefinisikan objek status Anda: kelas {@link android.preference.Preference.BaseSavedState}.
Untuk mendefinisikan cara kelas {@link android.preference.Preference} menyimpan statusnya, Anda harus memperluas kelas {@link android.preference.Preference.BaseSavedState}. Anda hanya perlu mengesampingkan beberapa metode dan mendefinisikan objek {@link android.preference.Preference.BaseSavedState#CREATOR} .
Untuk sebagian besar aplikasi, Anda bisa menyalin implementasi berikut dan cukup mengubah baris yang menangani {@code value} jika subkelas {@link android.preference.Preference} Anda menyimpan tipe data selain integer.
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]; } }; }
Dengan implementasi {@link android.preference.Preference.BaseSavedState} di atas yang ditambahkan ke aplikasi Anda (biasanya sebagai subkelas dari subkelas {@link android.preference.Preference}), Anda nanti perlu mengimplementasikan metode {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} dan {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} untuk subkelas {@link android.preference.Preference} Anda.
Misalnya:
@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); }