Mengambil daftar kontak

Tutorial ini menjelaskan cara mengambil daftar kontak yang datanya cocok dengan semua atau sebagian string penelusuran, menggunakan teknik berikut:

Mencocokkan nama kontak
Ambil daftar kontak dengan mencocokkan string penelusuran ke semua atau sebagian data nama kontak. Penyedia Kontak mendukung beberapa instance nama yang sama, sehingga teknik ini dapat menampilkan daftar kecocokan.
Mencocokkan jenis data tertentu, seperti nomor telepon
Ambil daftar kontak dengan mencocokkan string penelusuran ke jenis data detail tertentu, seperti alamat email. Misalnya, teknik ini memungkinkan Anda mencantumkan semua kontak yang alamat emailnya cocok dengan string penelusuran.
Mencocokkan segala jenis data
Ambil daftar kontak dengan mencocokkan string penelusuran ke segala jenis data detail, termasuk nama, nomor telepon, alamat jalan, alamat email, dan sebagainya. Misalnya, teknik ini memungkinkan Anda menerima segala jenis data untuk string penelusuran, lalu mencantumkan kontak yang datanya cocok dengan string.

Catatan: Semua contoh dalam tutorial ini menggunakan CursorLoader untuk mengambil data dari Penyedia Kontak. CursorLoader menjalankan kuerinya pada thread yang terpisah dari UI thread. Hal ini memastikan bahwa kueri tidak memperlambat waktu respons UI dan menyebabkan pengalaman pengguna yang buruk. Untuk informasi selengkapnya, lihat kelas pelatihan Android Memuat Data di Latar Belakang.

Meminta izin untuk membaca penyedia

Untuk melakukan jenis penelusuran apa pun pada Penyedia Kontak, aplikasi Anda harus memiliki izin READ_CONTACTS. Untuk meminta izin ini, tambahkan elemen <uses-permission> ke file manifes sebagai elemen turunan <manifest>:

        <uses-permission android:name="android.permission.READ_CONTACTS" />
    

Mencocokkan kontak menurut nama dan mencantumkan hasilnya

Teknik ini mencoba mencocokkan string penelusuran ke nama kontak atau kontak dalam tabel ContactsContract.Contacts Penyedia Kontak. Biasanya Anda ingin menampilkan hasil dalam ListView, agar pengguna dapat memilih di antara kontak yang cocok.

Menentukan ListView dan tata letak item

Untuk menampilkan hasil penelusuran di ListView, Anda memerlukan file tata letak utama yang menentukan seluruh UI termasuk ListView, dan file tata letak item yang menentukan satu baris ListView. Misalnya, Anda dapat membuat file tata letak utama res/layout/contacts_list_view.xml dengan XML berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@android:id/list"
              android:layout_width="match_parent"
              android:layout_height="match_parent"/>
    

XML ini menggunakan widget ListView Android bawaan android:id/list.

Tentukan contacts_list_item.xml file tata letak item dengan XML berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@android:id/text1"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:clickable="true"/>
    

XML ini menggunakan widget TextView Android bawaan android:text1.

Catatan: Tutorial ini tidak menjelaskan UI untuk mendapatkan string penelusuran dari pengguna, karena Anda mungkin ingin mendapatkan string tersebut secara tidak langsung. Misalnya, Anda dapat memberi pengguna opsi untuk menelusuri kontak yang namanya cocok dengan string dalam pesan teks yang masuk.

Kedua file tata letak yang Anda tulis menentukan antarmuka pengguna yang menunjukkan ListView. Langkah selanjutnya adalah menulis kode yang menggunakan UI ini untuk menampilkan daftar kontak.

Menetapkan Fragment yang menampilkan daftar kontak

Untuk menampilkan daftar kontak, mulailah dengan menentukan Fragment yang dimuat oleh suatu Activity. Menggunakan Fragment adalah teknik yang lebih fleksibel, karena Anda dapat menggunakan Fragment pertama untuk menampilkan daftar dan Fragment kedua untuk menampilkan detail kontak yang dipilih pengguna dari daftar. Dengan pendekatan ini, Anda dapat menggabungkan salah satu teknik yang dijelaskan dalam tutorial ini dengan teknik dari tutorial Mengambil detail untuk kontak.

Untuk mempelajari cara menggunakan satu atau beberapa objek Fragment dari Activity, baca kelas pelatihan Mem-build UI dinamis dengan Fragment.

Untuk membantu Anda menulis kueri terhadap Penyedia Kontak, framework Android menyediakan kelas kontrak yang disebut ContactsContract, yang menentukan konstanta dan metode yang berguna untuk mengakses penyedia. Saat menggunakan class ini, Anda tidak perlu menentukan konstanta Anda sendiri untuk URI konten, nama tabel, atau kolom. Untuk menggunakan class ini, sertakan pernyataan berikut:

Kotlin

    import android.provider.ContactsContract
    

Java

    import android.provider.ContactsContract;
    

Karena kode ini menggunakan CursorLoader untuk mengambil data dari penyedia, Anda harus menetapkan bahwa kode tersebut mengimplementasikan antarmuka loader LoaderManager.LoaderCallbacks. Selain itu, untuk membantu mendeteksi kontak mana yang dipilih pengguna dari daftar hasil penelusuran, implementasikan antarmuka adaptor AdapterView.OnItemClickListener. Contoh:

Kotlin

    ...
    import android.support.v4.app.Fragment
    import android.support.v4.app.LoaderManager
    import android.widget.AdapterView
    ...
    class ContactsFragment :
            Fragment(),
            LoaderManager.LoaderCallbacks<Cursor>,
            AdapterView.OnItemClickListener {
    

Java

    ...
    import android.support.v4.app.Fragment;
    import android.support.v4.app.LoaderManager.LoaderCallbacks;
    import android.widget.AdapterView;
    ...
    public class ContactsFragment extends Fragment implements
            LoaderManager.LoaderCallbacks<Cursor>,
            AdapterView.OnItemClickListener {
    

Menentukan variabel global

Tentukan variabel global yang digunakan di bagian lain kode:

Kotlin

    ...
    /*
     * Defines an array that contains column names to move from
     * the Cursor to the ListView.
     */
    @SuppressLint("InlinedApi")
    private val FROM_COLUMNS: Array<String> = arrayOf(
            if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) {
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            } else {
                ContactsContract.Contacts.DISPLAY_NAME
            }
    )
    /*
     * Defines an array that contains resource ids for the layout views
     * that get the Cursor column contents. The id is pre-defined in
     * the Android framework, so it is prefaced with "android.R.id"
     */
    private val TO_IDS: IntArray = intArrayOf(android.R.id.text1)
    ...
    class ContactsFragment :
            Fragment(),
            LoaderManager.LoaderCallbacks<Cursor>,
            AdapterView.OnItemClickListener {
        ...
        // Define global mutable variables
        // Define a ListView object
        lateinit var contactsList: ListView
        // Define variables for the contact the user selects
        // The contact's _ID value
        var contactId: Long = 0
        // The contact's LOOKUP_KEY
        var contactKey: String? = null
        // A content URI for the selected contact
        var contactUri: Uri? = null
        // An adapter that binds the result Cursor to the ListView
        private val cursorAdapter: SimpleCursorAdapter? = null

    

Java

        ...
        /*
         * Defines an array that contains column names to move from
         * the Cursor to the ListView.
         */
        @SuppressLint("InlinedApi")
        private final static String[] FROM_COLUMNS = {
                Build.VERSION.SDK_INT
                        >= Build.VERSION_CODES.HONEYCOMB ?
                        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY :
                        ContactsContract.Contacts.DISPLAY_NAME
        };
        /*
         * Defines an array that contains resource ids for the layout views
         * that get the Cursor column contents. The id is pre-defined in
         * the Android framework, so it is prefaced with "android.R.id"
         */
        private final static int[] TO_IDS = {
               android.R.id.text1
        };
        // Define global mutable variables
        // Define a ListView object
        ListView contactsList;
        // Define variables for the contact the user selects
        // The contact's _ID value
        long contactId;
        // The contact's LOOKUP_KEY
        String contactKey;
        // A content URI for the selected contact
        Uri contactUri;
        // An adapter that binds the result Cursor to the ListView
        private SimpleCursorAdapter cursorAdapter;
        ...
    

Catatan: Karena Contacts.DISPLAY_NAME_PRIMARY memerlukan Android 3.0 (API versi 11) atau yang lebih baru, menetapkan minSdkVersion aplikasi ke 10 atau versi di bawahnya akan menghasilkan peringatan Android Lint di Android Studio. Untuk menonaktifkan peringatan ini, tambahkan anotasi @SuppressLint("InlinedApi") sebelum definisi FROM_COLUMNS.

Menginisialisasi Fragment

Inisialisasi Fragment. Tambahkan konstruktor publik kosong yang diperlukan oleh sistem Android, dan perluas UI objek Fragment dalam metode callback onCreateView(). Contoh:

Kotlin

        // A UI Fragment must inflate its View
        override fun onCreateView(
                inflater: LayoutInflater,
                container: ViewGroup?,
                savedInstanceState: Bundle?
        ): View? {
            // Inflate the fragment layout
            return inflater.inflate(R.layout.contact_list_fragment, container, false)
        }
    

Java

        // Empty public constructor, required by the system
        public ContactsFragment() {}

        // A UI Fragment must inflate its View
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            // Inflate the fragment layout
            return inflater.inflate(R.layout.contact_list_fragment,
                container, false);
        }
    

Menyiapkan CursorAdapter untuk ListView

Siapkan SimpleCursorAdapter yang mengikat hasil penelusuran ke ListView. Untuk mendapatkan objek ListView yang menampilkan kontak, Anda harus memanggil Activity.findViewById() menggunakan aktivitas induk Fragment. Gunakan Context dari aktivitas induk saat Anda memanggil setAdapter(). Contoh:

Kotlin

        override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
            ...
            // Gets the ListView from the View list of the parent activity
            activity?.also {
                contactsList = it.findViewById<ListView>(R.id.contact_list_view)
                // Gets a CursorAdapter
                cursorAdapter = SimpleCursorAdapter(
                        it,
                        R.layout.contact_list_item,
                        null,
                        FROM_COLUMNS, TO_IDS,
                        0
                )
                // Sets the adapter for the ListView
                contactsList.adapter = cursorAdapter
            }
        }
    

Java

        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            ...
            // Gets the ListView from the View list of the parent activity
            contactsList =
                (ListView) getActivity().findViewById(R.layout.contact_list_view);
            // Gets a CursorAdapter
            cursorAdapter = new SimpleCursorAdapter(
                    getActivity(),
                    R.layout.contact_list_item,
                    null,
                    FROM_COLUMNS, TO_IDS,
                    0);
            // Sets the adapter for the ListView
            contactsList.setAdapter(cursorAdapter);
        }
    

Menetapkan pemroses kontak yang dipilih

Saat menampilkan hasil penelusuran, biasanya Anda perlu mengizinkan pengguna memilih satu kontak untuk diproses lebih lanjut. Misalnya, saat pengguna mengklik sebuah kontak, Anda dapat menampilkan alamat kontak tersebut pada peta. Untuk menyediakan fitur ini, pertama-tama Anda harus menentukan Fragment saat ini sebagai pemroses klik dengan menentukan bahwa class mengimplementasikan AdapterView.OnItemClickListener, seperti yang ditunjukkan pada bagian Menentukan Fragment yang menampilkan daftar kontak.

Untuk terus menyiapkan pemroses, ikat ke ListView dengan memanggil metode setOnItemClickListener() di onActivityCreated(). Contoh:

Kotlin

        fun onActivityCreated(savedInstanceState:Bundle) {
            ...
            // Set the item click listener to be the current fragment.
            contactsList.onItemClickListener = this
            ...
        }
    

Java

        public void onActivityCreated(Bundle savedInstanceState) {
            ...
            // Set the item click listener to be the current fragment.
            contactsList.setOnItemClickListener(this);
            ...
        }
    

Karena menentukan Fragment saat ini adalah OnItemClickListener untuk ListView, Anda sekarang harus mengimplementasikan metode yang diperlukan onItemClick(), yang menangani peristiwa klik. Hal ini dijelaskan di bagian selanjutnya.

Menentukan proyeksi

Tentukan konstanta yang berisi kolom-kolom yang ingin Anda tampilkan dari kueri Anda. Setiap item dalam ListView menampilkan nama yang ditampilkan kontak, yang berisi bentuk utama nama kontak. Di Android 3.0 (API versi 11) dan yang lebih baru, nama kolom ini adalah Contacts.DISPLAY_NAME_PRIMARY; di versi sebelumnya, namanya adalah Contacts.DISPLAY_NAME.

Kolom Contacts._ID digunakan oleh proses binding SimpleCursorAdapter. Contacts._ID dan LOOKUP_KEY digunakan bersama-sama untuk membuat URI konten bagi kontak yang dipilih pengguna.

Kotlin

    ...
    @SuppressLint("InlinedApi")
    private val PROJECTION: Array<out String> = arrayOf(
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.LOOKUP_KEY,
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            else
                ContactsContract.Contacts.DISPLAY_NAME
    )
    

Java

    ...
    @SuppressLint("InlinedApi")
    private static final String[] PROJECTION =
            {
                Contacts._ID,
                Contacts.LOOKUP_KEY,
                Build.VERSION.SDK_INT
                        >= Build.VERSION_CODES.HONEYCOMB ?
                        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY :
                        ContactsContract.Contacts.DISPLAY_NAME

            };
    

Menentukan konstanta untuk indeks kolom Cursor

Untuk mendapatkan data dari kolom tertentu dalam Cursor, Anda memerlukan indeks kolom di dalam Cursor. Anda dapat menentukan konstanta untuk indeks kolom Cursor, karena indeks ini sama dengan urutan nama kolom dalam proyeksi Anda. Contoh:

Kotlin

    // The column index for the _ID column
    private const val CONTACT_ID_INDEX: Int = 0
    // The column index for the CONTACT_KEY column
    private const val CONTACT_KEY_INDEX: Int = 1
    

Java

    // The column index for the _ID column
    private static final int CONTACT_ID_INDEX = 0;
    // The column index for the CONTACT_KEY column
    private static final int CONTACT_KEY_INDEX = 1;
    

Menetapkan kriteria pemilihan

Untuk menetapkan data yang diinginkan, buatlah kombinasi ekspresi teks dan variabel yang memberitahukan data yang akan ditelusuri dan nilai yang akan ditemukan kepada penyedia kolom.

Untuk ekspresi teks, tentukan konstanta yang mencantumkan kolom penelusuran. Meskipun ekspresi ini juga dapat berisi nilai, praktik pilihannya adalah mewakili nilai dengan placeholder "?". Selama pengambilan data, placeholder diganti dengan nilai dari array. Menggunakan "?" sebagai placeholder memastikan bahwa spesifikasi penelusuran dihasilkan melalui binding, bukan kompilasi SQL. Praktik ini menghilangkan kemungkinan injeksi SQL yang berbahaya. Contoh:

Kotlin

    // Defines the text expression
    @SuppressLint("InlinedApi")
    private val SELECTION: String =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?"
            else
                "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?"
    ...
        // Defines a variable for the search string
        private val searchString: String = ...
        // Defines the array to hold values that replace the ?
        private val selectionArgs = arrayOf<String>(searchString)
    

Java

        // Defines the text expression
        @SuppressLint("InlinedApi")
        private static final String SELECTION =
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
                Contacts.DISPLAY_NAME + " LIKE ?";
        // Defines a variable for the search string
        private String searchString;
        // Defines the array to hold values that replace the ?
        private String[] selectionArgs = { searchString };
    

Menentukan metode onItemClick()

Di bagian sebelumnya, Anda menetapkan pemroses klik item untuk ListView. Sekarang implementasikan tindakan untuk pemroses dengan menentukan metode AdapterView.OnItemClickListener.onItemClick():

Kotlin

        override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
            // Get the Cursor
            val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply {
                // Move to the selected contact
                moveToPosition(position)
                // Get the _ID value
                contactId = getLong(CONTACT_ID_INDEX)
                // Get the selected LOOKUP KEY
                contactKey = getString(CONTACT_KEY_INDEX)
                // Create the contact's content Uri
                contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey)
                /*
                 * You can use contactUri as the content URI for retrieving
                 * the details for a contact.
                 */
            }
        }
    

Java

        @Override
        public void onItemClick(
            AdapterView<?> parent, View item, int position, long rowID) {
            // Get the Cursor
            Cursor cursor = parent.getAdapter().getCursor();
            // Move to the selected contact
            cursor.moveToPosition(position);
            // Get the _ID value
            contactId = cursor.getLong(CONTACT_ID_INDEX);
            // Get the selected LOOKUP KEY
            contactKey = cursor.getString(CONTACT_KEY_INDEX);
            // Create the contact's content Uri
            contactUri = Contacts.getLookupUri(contactId, mContactKey);
            /*
             * You can use contactUri as the content URI for retrieving
             * the details for a contact.
             */
        }
    

Menginisialisasi loader

Karena menggunakan CursorLoader untuk mengambil data, Anda harus menginisialisasi thread latar belakang dan variabel lain yang mengontrol pengambilan data secara asinkron. Lakukan inisialisasi dalam onCreate() seperti yang ditunjukkan pada contoh berikut:

Kotlin

    class ContactsFragment :
            Fragment(),
            LoaderManager.LoaderCallbacks<Cursor> {
        ...
        override fun onCreate(savedInstanceState: Bundle?) {
            // Always call the super method first
            super.onCreate(savedInstanceState)
            ...
            // Initializes the loader
            loaderManager.initLoader(0, null, this)
    

Java

    public class ContactsFragment extends Fragment implements
            LoaderManager.LoaderCallbacks<Cursor> {
        ...
        // Called just before the Fragment displays its UI
        @Override
        public void onCreate(Bundle savedInstanceState) {
            // Always call the super method first
            super.onCreate(savedInstanceState);
            ...
            // Initializes the loader
            getLoaderManager().initLoader(0, null, this);
    

Mengimplementasikan onCreateLoader()

Implementasikan metode onCreateLoader(), yang dipanggil oleh framework loader segera setelah Anda memanggil initLoader().

Di onCreateLoader(), siapkan pola string penelusuran. Untuk mengubah string menjadi suatu pola, sisipkan karakter "%" (persen) untuk mewakili rangkaian yang terdiri dari nol atau beberapa karakter, atau karakter "_" (garis bawah) untuk mewakili karakter tunggal, atau keduanya. Misalnya, pola "%Sandra%" akan cocok dengan "Dewi Sandra" dan juga "Sandra Bullock".

Tampilkan CursorLoader baru dari metode. Untuk URI konten, gunakan Contacts.CONTENT_URI. URI ini merujuk ke seluruh tabel, seperti yang ditunjukkan dalam contoh berikut:

Kotlin

        ...
        override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
            /*
             * Makes search string into pattern and
             * stores it in the selection array
             */
            selectionArgs[0] = "%$mSearchString%"
            // Starts the query
            return activity?.let {
                return CursorLoader(
                        it,
                        ContactsContract.Contacts.CONTENT_URI,
                        PROJECTION,
                        SELECTION,
                        selectionArgs,
                        null
                )
            } ?: throw IllegalStateException()
        }
    

Java

        ...
        @Override
        public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
            /*
             * Makes search string into pattern and
             * stores it in the selection array
             */
            selectionArgs[0] = "%" + searchString + "%";
            // Starts the query
            return new CursorLoader(
                    getActivity(),
                    ContactsContract.Contacts.CONTENT_URI,
                    PROJECTION,
                    SELECTION,
                    selectionArgs,
                    null
            );
        }
    

Mengimplementasikan onLoadFinished() dan onLoaderReset()

Implementasikan metode onLoadFinished(). Framework loader ini memanggil onLoadFinished() saat Penyedia Kontak menampilkan hasil kueri. Dalam metode ini, tempatkan hasil Cursor dalam SimpleCursorAdapter. Cara ini akan otomatis mengupdate ListView dengan hasil penelusuran:

Kotlin

        override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
            // Put the result Cursor in the adapter for the ListView
            cursorAdapter?.swapCursor(cursor)
        }
    

Java

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            // Put the result Cursor in the adapter for the ListView
            cursorAdapter.swapCursor(cursor);
        }
    

Metode onLoaderReset() dipanggil saat framework loader mendeteksi bahwa hasil Cursor berisi data yang usang. Hapus referensi SimpleCursorAdapter ke Cursor yang ada. Jika tidak, framework loader tidak akan mendaur ulang Cursor, dan terjadilah kebocoran memori. Contoh:

Kotlin

        override fun onLoaderReset(loader: Loader<Cursor>) {
            // Delete the reference to the existing Cursor
            cursorAdapter?.swapCursor(null)
        }
    

Java

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            // Delete the reference to the existing Cursor
            cursorAdapter.swapCursor(null);

        }
    

Sekarang Anda memiliki bagian penting dari aplikasi yang mencocokkan string penelusuran dengan nama kontak dan menampilkan hasilnya di ListView. Pengguna dapat mengklik nama kontak untuk memilihnya. Hal ini akan memicu pemroses, yang memungkinkan Anda menangani data kontak lebih jauh. Misalnya, Anda dapat mengambil detail kontak. Untuk mempelajari cara melakukannya, lanjutkan ke tutorial berikutnya, Mengambil detail untuk kontak.

Untuk mempelajari antarmuka pengguna penelusuran lebih lanjut, baca panduan API Membuat antarmuka penelusuran.

Bagian selanjutnya dalam tutorial ini akan menunjukkan cara lain untuk menemukan kontak di Penyedia Kontak.

Mencocokkan kontak menurut jenis data tertentu

Teknik ini memungkinkan Anda menetapkan jenis data yang ingin dicocokkan. Pengambilan data menurut nama adalah contoh spesifik dari jenis kueri ini, tetapi Anda juga dapat melakukannya untuk jenis data detail apa pun yang terkait dengan kontak. Misalnya, Anda dapat mengambil kontak yang memiliki kode pos tertentu; dalam hal ini, string penelusuran harus cocok dengan data yang tersimpan dalam baris kode pos.

Untuk menerapkan jenis pengambilan ini, pertama-tama terapkan kode berikut, seperti yang tercantum di bagian sebelumnya:

  • Meminta Izin untuk Membaca Penyedia.
  • Menentukan ListView dan tata letak item.
  • Menetapkan Fragment yang menampilkan daftar kontak.
  • Menentukan variabel global.
  • Menginisialisasi Fragment.
  • Menyiapkan CursorAdapter untuk ListView.
  • Menetapkan pemroses kontak yang dipilih.
  • Menentukan konstanta untuk indeks kolom Cursor.

    Meskipun Anda mengambil data dari tabel berbeda, urutan kolom dalam proyeksi ini tetap sama, sehingga Anda dapat menggunakan indeks yang sama untuk Cursor.

  • Menentukan metode onItemClick().
  • Menginisialisasi loader.
  • Menerapkan onLoadFinished() dan onLoaderReset().

Langkah-langkah berikut menunjukkan kode tambahan yang Anda perlukan untuk mencocokkan string penelusuran dengan jenis data detail tertentu dan menampilkan hasilnya.

Memilih jenis data dan tabel

Untuk menelusuri jenis data detail tertentu, Anda harus mengetahui nilai jenis MIME kustom untuk jenis data tersebut. Setiap jenis data memiliki nilai jenis MIME unik yang ditentukan oleh konstanta CONTENT_ITEM_TYPE dalam subclass ContactsContract.CommonDataKinds yang dikaitkan dengan jenis data. Subclass memiliki nama yang menunjukkan jenis datanya; contoh, subclass untuk data email adalah ContactsContract.CommonDataKinds.Email, dan jenis MIME kustom untuk data email ditentukan oleh konstanta Email.CONTENT_ITEM_TYPE.

Gunakan tabel ContactsContract.Data untuk penelusuran Anda. Semua konstanta yang diperlukan untuk proyeksi, klausa pemilihan, dan urutan penyortiran ditentukan dalam atau diwarisi oleh tabel ini.

Menentukan proyeksi

Untuk menentukan proyeksi, pilih satu atau beberapa kolom yang ditentukan dalam ContactsContract.Data atau class asal kolom yang diwarisi oleh proyeksi. Penyedia Kontak melakukan penggabungan implisit antara ContactsContract.Data dan tabel lainnya sebelum menampilkan baris. Contoh:

Kotlin

    @SuppressLint("InlinedApi")
    private val PROJECTION: Array<out String> = arrayOf(
            /*
             * The detail data row ID. To make a ListView work,
             * this column is required.
             */
            ContactsContract.Data._ID,
            // The primary display name
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                ContactsContract.Data.DISPLAY_NAME_PRIMARY
            else
                ContactsContract.Data.DISPLAY_NAME,
            // The contact's _ID, to construct a content URI
            ContactsContract.Data.CONTACT_ID,
            // The contact's LOOKUP_KEY, to construct a content URI
            ContactsContract.Data.LOOKUP_KEY
    )
    

Java

        @SuppressLint("InlinedApi")
        private static final String[] PROJECTION =
            {
                /*
                 * The detail data row ID. To make a ListView work,
                 * this column is required.
                 */
                ContactsContract.Data._ID,
                // The primary display name
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                        ContactsContract.Data.DISPLAY_NAME_PRIMARY :
                        ContactsContract.Data.DISPLAY_NAME,
                // The contact's _ID, to construct a content URI
                ContactsContract.Data.CONTACT_ID,
                // The contact's LOOKUP_KEY, to construct a content URI
                ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact
            };
    

Menentukan kriteria penelusuran

Untuk menelusuri sebuah string dalam jenis data tertentu, buatlah klausa pemilihan dari berikut ini:

  • Nama kolom yang berisi string penelusuran Anda. Nama ini bervariasi menurut jenis data, sehingga Anda perlu menemukan subclass ContactsContract.CommonDataKinds yang sesuai dengan jenis datanya, lalu memilih nama kolom dari subclass tersebut. Misalnya, untuk menelusuri alamat email, gunakan kolom Email.ADDRESS.
  • String penelusuran itu sendiri, direpresentasikan sebagai karakter "?" dalam klausa pemilihan.
  • Nama kolom yang berisi nilai jenis MIME kustom. Nama ini selalu Data.MIMETYPE.
  • Nilai jenis MIME kustom untuk jenis data itu. Seperti yang dijelaskan sebelumnya, ini adalah konstanta CONTENT_ITEM_TYPE dalam subclass ContactsContract.CommonDataKinds. Misalnya, nilai jenis MIME untuk data email adalah Email.CONTENT_ITEM_TYPE. Tempatkan nilai ini di antara tanda kutip tunggal dengan menambahkan karakter "'" (kutip tunggal) ke awal dan akhir konstanta; jika tidak, penyedia akan menafsirkan nilai itu 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

    /*
     * Constructs search criteria from the search string
     * and email MIME type
     */
    private val SELECTION: String =
            /*
             * Searches for an email address
             * that matches the search string
             */
            "${Email.ADDRESS} LIKE ? AND " +
            /*
             * Searches for a MIME type that matches
             * the value of the constant
             * Email.CONTENT_ITEM_TYPE. Note the
             * single quotes surrounding Email.CONTENT_ITEM_TYPE.
             */
            "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
    

Java

        /*
         * Constructs search criteria from the search string
         * and email MIME type
         */
        private static final String SELECTION =
                /*
                 * Searches for an email address
                 * that matches the search string
                 */
                Email.ADDRESS + " LIKE ? " + "AND " +
                /*
                 * Searches for a MIME type that matches
                 * the value of the constant
                 * Email.CONTENT_ITEM_TYPE. Note the
                 * single quotes surrounding Email.CONTENT_ITEM_TYPE.
                 */
                ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
    

Selanjutnya, tentukan variabel yang akan memuat argumen pemilihan:

Kotlin

        private var searchString: String? = null
        private val selectionArgs: Array<String> = arrayOf("")
    

Java

        String searchString;
        String[] selectionArgs = { "" };
    

Mengimplementasikan onCreateLoader()

Setelah menetapkan data yang Anda inginkan dan cara menemukannya, sekarang tentukan kueri dalam implementasi onCreateLoader() Anda. Tampilkan CursorLoader baru dari metode ini, menggunakan proyeksi, ekspresi teks pemilihan, dan array pemilihan sebagai argumen. Untuk URI konten, gunakan Data.CONTENT_URI. Contoh:

Kotlin

        override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
            // OPTIONAL: Makes search string into pattern
            searchString = "%$mSearchString%"

            searchString?.also {
                // Puts the search string into the selection criteria
                selectionArgs[0] = it
            }
            // Starts the query
            return activity?.let {
                CursorLoader(
                        it,
                        ContactsContract.Data.CONTENT_URI,
                        PROJECTION,
                        SELECTION,
                        selectionArgs,
                        null
                )
            } ?: throw IllegalStateException()
        }
    

Java

    @Override
        public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
            // OPTIONAL: Makes search string into pattern
            searchString = "%" + searchString + "%";
            // Puts the search string into the selection criteria
            selectionArgs[0] = searchString;
            // Starts the query
            return new CursorLoader(
                    getActivity(),
                    Data.CONTENT_URI,
                    PROJECTION,
                    SELECTION,
                    selectionArgs,
                    null
            );
        }
    

Cuplikan kode ini adalah dasar dari pencarian terbalik sederhana yang didasarkan pada jenis data detail tertentu. Ini adalah teknik terbaik yang bisa digunakan jika aplikasi Anda berfokus pada jenis data tertentu, seperti email, dan Anda ingin mengizinkan pengguna mendapatkan nama yang terkait dengan data tertentu.

Mencocokkan kontak menurut sembarang jenis data

Mengambil kontak berdasarkan sembarang jenis data akan menampilkan kontak jika ada datanya yang cocok dengan string penelusuran, termasuk nama, alamat email, alamat pos, nomor telepon, dan sebagainya. Cara ini menghasilkan hasil penelusuran yang luas. Misalnya, jika string penelusuran Anda adalah "Indra", maka menelusuri sembarang jenis data akan menampilkan kontak "Dewi Indra"; string penelusuran ini juga menampilkan kontak yang tinggal di "Jalan Indra".

Untuk menerapkan jenis pengambilan ini, pertama-tama terapkan kode berikut, seperti yang tercantum di bagian sebelumnya:

  • Meminta Izin untuk Membaca Penyedia.
  • Menentukan ListView dan tata letak item.
  • Menetapkan Fragment yang menampilkan daftar kontak.
  • Menentukan variabel global.
  • Menginisialisasi Fragment.
  • Menyiapkan CursorAdapter untuk ListView.
  • Menetapkan pemroses kontak yang dipilih.
  • Menentukan proyeksi.
  • Menentukan konstanta untuk indeks kolom Cursor.

    Untuk jenis pengambilan ini, Anda menggunakan tabel yang sama dengan yang digunakan di bagian Mencocokkan kontak menurut nama dan mencantumkan hasilnya. Gunakan indeks kolom yang sama juga.

  • Menentukan metode onItemClick().
  • Menginisialisasi loader.
  • Menerapkan onLoadFinished() dan onLoaderReset().

Langkah-langkah berikut menunjukkan kode tambahan yang Anda perlukan untuk mencocokkan string penelusuran dengan sembarang jenis data dan menampilkan hasilnya.

Menghapus kriteria pemilihan

Jangan menentukan konstanta SELECTION atau variabel mSelectionArgs. Keduanya tidak digunakan dalam jenis pengambilan ini.

Mengimplementasikan onCreateLoader()

Implementasikan metode onCreateLoader(), yang menampilkan CursorLoader yang baru. Anda tidak perlu mengubah string penelusuran menjadi suatu pola, karena Penyedia Kontak melakukannya secara otomatis. Gunakan Contacts.CONTENT_FILTER_URI sebagai URI dasar, lalu tambahkan string penelusuran Anda dengan memanggil Uri.withAppendedPath(). Penggunaan URI ini otomatis memicu penelusuran untuk segala jenis data, seperti yang ditunjukkan dalam contoh berikut:

Kotlin

        override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
            /*
             * Appends the search string to the base URI. Always
             * encode search strings to ensure they're in proper
             * format.
             */
            val contentUri: Uri = Uri.withAppendedPath(
                    ContactsContract.Contacts.CONTENT_FILTER_URI,
                    Uri.encode(searchString)
            )
            // Starts the query
            return activity?.let {
                CursorLoader(
                        it,
                        contentUri,
                        PROJECTION2,
                        null,
                        null,
                        null
                )
            } ?: throw IllegalStateException()
        }
    

Java

        @Override
        public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
            /*
             * Appends the search string to the base URI. Always
             * encode search strings to ensure they're in proper
             * format.
             */
            Uri contentUri = Uri.withAppendedPath(
                    Contacts.CONTENT_FILTER_URI,
                    Uri.encode(searchString));
            // Starts the query
            return new CursorLoader(
                    getActivity(),
                    contentUri,
                    PROJECTION,
                    null,
                    null,
                    null
            );
        }
    

Cuplikan kode ini adalah dasar dari aplikasi yang melakukan penelusuran yang luas terhadap Penyedia Kontak. Teknik ini berguna untuk aplikasi yang ingin mengimplementasikan fungsionalitas yang mirip dengan layar daftar kontak pada aplikasi Orang.