Pelajaran ini menunjukkan cara mengambil data detail untuk kontak, seperti alamat email, nomor telepon, dan sebagainya. Itulah detail yang dicari pengguna saat mereka mengambil kontak. Anda dapat memberikan semua detail kontak, atau hanya menampilkan detail jenis tertentu, seperti alamat email.
Langkah-langkah dalam pelajaran ini mengasumsikan bahwa Anda sudah memiliki
baris ContactsContract.Contacts untuk kontak yang dipilih pengguna.
Pelajaran Mengambil nama kontak menunjukkan cara
mengambil daftar kontak.
Mengambil semua detail kontak
Untuk mengambil semua detail kontak, telusuri tabel
ContactsContract.Data untuk menemukan baris yang berisi
LOOKUP_KEY kontak. Kolom ini tersedia di
tabel ContactsContract.Data, karena Penyedia
Kontak membuat penggabungan implisit antara tabel
ContactsContract.Contacts dan tabel ContactsContract.Data. Kolom
LOOKUP_KEY dijelaskan
secara lebih mendetail dalam pelajaran Mengambil nama kontak.
Catatan: Mengambil semua detail kontak akan mengurangi performa
perangkat, karena harus mengambil semua kolom dalam
tabel ContactsContract.Data. Pertimbangkan dampak performa sebelum
Anda menggunakan teknik ini.
Meminta izin
Untuk membaca dari Penyedia Kontak, aplikasi Anda harus memiliki izin READ_CONTACTS.
Untuk meminta izin ini, tambahkan elemen turunan berikut dari
<manifest> ke file manifes Anda:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Menyiapkan proyeksi
Tergantung jenis data yang dimuat oleh baris, data mungkin menggunakan sedikit atau banyak kolom. Selain itu,
data berada di kolom yang berbeda, bergantung pada jenis datanya.
Untuk memastikan Anda mendapatkan semua kemungkinan kolom untuk semua kemungkinan jenis data, Anda perlu menambahkan semua
nama kolom ke proyeksi Anda. Selalu ambil
Data._ID jika Anda mengikat hasil
Cursor ke ListView; jika tidak, pengikatan
tidak akan berfungsi. Ambil juga Data.MIMETYPE
sehingga Anda dapat mengidentifikasi jenis data setiap baris yang diambil. Contoh:
Kotlin
private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 )
Java
private static final String[] PROJECTION = { ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 };
Proyeksi ini mengambil semua kolom untuk baris dalam
tabel ContactsContract.Data, menggunakan nama kolom yang ditentukan di
class ContactsContract.Data.
Secara opsional, Anda juga dapat menggunakan konstanta kolom lain yang ditentukan dalam atau diwarisi oleh
class ContactsContract.Data. Namun, perhatikan bahwa kolom
SYNC1 hingga
SYNC4 dimaksudkan untuk digunakan oleh adaptor
sinkronisasi, sehingga datanya tidak berguna.
Menentukan kriteria pemilihan
Tentukan konstanta untuk klausa pilihan, array untuk menyimpan argumen pilihan, dan
variabel untuk menyimpan nilai pilihan. Gunakan
kolom Contacts.LOOKUP_KEY untuk
menemukan kontak. Contoh:
Kotlin
// Defines the selection clause private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("") /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private var lookupKey: String? = null
Java
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" }; /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private lateinit var lookupKey: String
Menggunakan "?" sebagai placeholder dalam ekspresi teks pilihan akan memastikan bahwa penelusuran yang dihasilkan dibuat oleh binding, bukan kompilasi SQL. Pendekatan ini menghilangkan kemungkinan injeksi SQL berbahaya.
Menentukan urutan penyortiran
Tetapkan urutan penyortiran yang Anda inginkan dalam Cursor yang dihasilkan. Agar
semua baris untuk jenis data tertentu tetap bersama, urutkan berdasarkan
Data.MIMETYPE. Argumen kueri ini
mengelompokkan semua baris email, semua baris telepon, dan sebagainya. Contoh:
Kotlin
/* * Defines a string that specifies a sort order of MIME type */ private const val SORT_ORDER = ContactsContract.Data.MIMETYPE
Java
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;
Catatan: Beberapa jenis data tidak menggunakan subjenis, jadi Anda tidak dapat menyortir menurut subjenis.
Sebagai gantinya, Anda harus melakukan iterasi pada Cursor yang ditampilkan,
menentukan jenis data baris saat ini, dan menyimpan data untuk baris yang menggunakan subjenis. Setelah
selesai membaca kursor, Anda dapat mengurutkan setiap jenis data menurut subjenis dan menampilkan
hasilnya.
Menginisialisasi loader
Selalu lakukan pengambilan dari Penyedia Kontak (dan semua penyedia konten lainnya) di
thread latar belakang. Gunakan framework Loader yang ditentukan oleh
class LoaderManager dan
antarmuka LoaderManager.LoaderCallbacks untuk melakukan pengambilan
di latar belakang.
Saat Anda siap mengambil baris, inisialisasi framework loader dengan
memanggil initLoader(). Teruskan
ID bilangan bulat ke metode; ID ini diteruskan ke
metode LoaderManager.LoaderCallbacks. ID ini membantu Anda
menggunakan beberapa pemuat dalam aplikasi dengan memungkinkan Anda membedakannya.
Cuplikan berikut menunjukkan cara menginisialisasi framework loader:
Kotlin
// Defines a constant that identifies the loader private const val DETAILS_QUERY_ID: Int = 0 class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Initializes the loader framework loaderManager.initLoader(DETAILS_QUERY_ID, null, this)
Java
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Defines a constant that identifies the loader static int DETAILS_QUERY_ID = 0; ... @Override public void onCreate(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
Menerapkan onCreateLoader()
Terapkan metode onCreateLoader(), yang dipanggil oleh framework loader segera setelah Anda memanggil
initLoader(). Tampilkan
CursorLoader dari metode ini. Karena Anda menelusuri
tabel ContactsContract.Data, gunakan konstanta
Data.CONTENT_URI sebagai URI konten.
Contoh:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { // Choose the proper action mLoader = when(loaderId) { DETAILS_QUERY_ID -> { // Assigns the selection parameter selectionArgs[0] = lookupKey // Starts the query activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } } ... } return mLoader }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter selectionArgs[0] = lookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ); }
Mengimplementasikan onLoadFinished() dan onLoaderReset()
Terapkan metode
onLoadFinished(). Framework loader memanggil
onLoadFinished()
saat Penyedia Kontak menampilkan hasil kueri. Contoh:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { when(loader.id) { DETAILS_QUERY_ID -> { /* * Process the resulting Cursor here. */ } ... } }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * Process the resulting Cursor here. */ } break; ... } }
Metode onLoaderReset() dipanggil saat framework loader mendeteksi bahwa data yang mendukung hasil
Cursor telah berubah. Pada tahap ini, hapus semua referensi yang ada
ke Cursor dengan menyetelnya ke null. Jika tidak, framework loader
tidak akan menghancurkan Cursor lama, dan Anda akan mengalami kebocoran
memori. Contoh:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { when (loader.id) { DETAILS_QUERY_ID -> { /* * If you have current references to the Cursor, * remove them here. */ } ... } }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * If you have current references to the Cursor, * remove them here. */ } break; }
Mengambil detail spesifik untuk sebuah kontak
Mengambil jenis data tertentu untuk kontak, seperti semua email, mengikuti pola yang sama dengan mengambil semua detail. Ini adalah satu-satunya perubahan yang perlu Anda lakukan pada kode yang tercantum dalam Mengambil semua detail untuk kontak:
- Proyeksi
-
Ubah proyeksi Anda untuk mengambil kolom yang spesifik untuk
jenis data. Ubah juga proyeksi untuk menggunakan konstanta nama kolom yang ditentukan dalam
subclass
ContactsContract.CommonDataKindsyang sesuai dengan jenis data. - Pilihan
-
Ubah teks pilihan untuk menelusuri nilai
MIMETYPEyang spesifik untuk jenis data Anda. - Tata urutan
-
Karena Anda hanya memilih satu jenis detail, jangan kelompokkan
Cursoryang ditampilkan berdasarkanData.MIMETYPE.
Modifikasi ini dijelaskan di bagian berikut.
Menentukan proyeksi
Tentukan kolom yang ingin Anda ambil, menggunakan konstanta nama kolom di subclass
ContactsContract.CommonDataKinds untuk jenis data.
Jika Anda berencana mengikat Cursor ke ListView,
pastikan untuk mengambil kolom _ID. Misalnya, untuk mengambil data email, tentukan
proyeksi berikut:
Kotlin
private val PROJECTION: Array<String> = arrayOf( ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL )
Java
private static final String[] PROJECTION = { ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL };
Perhatikan bahwa proyeksi ini menggunakan nama kolom yang ditentukan dalam class
ContactsContract.CommonDataKinds.Email, bukan nama kolom
yang ditentukan dalam class ContactsContract.Data. Menggunakan nama kolom khusus email akan membuat kode lebih mudah dibaca.
Dalam proyeksi, Anda juga dapat menggunakan kolom lain yang ditentukan dalam
subclass ContactsContract.CommonDataKinds.
Menentukan kriteria pemilihan
Tentukan ekspresi teks penelusuran yang mengambil baris untuk
LOOKUP_KEY kontak tertentu dan
Data.MIMETYPE detail yang Anda
inginkan. Sertakan nilai MIMETYPE dalam
tanda kutip tunggal dengan menggabungkan karakter "'" (tanda kutip tunggal) ke awal dan akhir
konstanta; jika tidak, penyedia akan menafsirkan konstanta sebagai nama variabel, bukan
sebagai nilai string. Anda tidak perlu menggunakan placeholder untuk nilai ini, karena Anda
menggunakan konstanta, bukan nilai yang disediakan pengguna. Contoh:
Kotlin
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private const val SELECTION = "${ContactsContract.Data.LOOKUP_KEY} = ? AND " + "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("")
Java
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private static final String SELECTION = Data.LOOKUP_KEY + " = ?" + " AND " + Data.MIMETYPE + " = " + "'" + Email.CONTENT_ITEM_TYPE + "'"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" };
Menentukan urutan penyortiran
Tetapkan urutan penyortiran untuk Cursor yang ditampilkan. Karena Anda mengambil
jenis data tertentu, hapus pengurutan pada MIMETYPE.
Sebagai gantinya, jika jenis data detail yang Anda telusuri menyertakan subjenis, lakukan penyortiran menurut subjenis tersebut.
Misalnya, untuk data email, Anda dapat mengurutkan berdasarkan
Email.TYPE:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";