Mengambil detail untuk kontak

Pelajaran ini menunjukkan cara mengambil data detail kontak, seperti alamat email, nomor telepon angka, 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 ContactsContract.Contacts baris 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 setiap baris yang berisi nama kontak LOOKUP_KEY. Kolom ini tersedia di tabel ContactsContract.Data, karena Penyedia Kontak membuat gabungan implisit antara tabel ContactsContract.Contacts dan tabel ContactsContract.Data. Tujuan Kolom LOOKUP_KEY dijelaskan secara lebih detail dalam pelajaran Mengambil nama kontak.

Catatan: Mengambil semua detail untuk sebuah kontak dapat menurunkan performa perangkat karena perangkat harus mengambil semua kolom dalam tabel ContactsContract.Data. Pertimbangkan dampak performa sebelum Anda akan menggunakan teknik ini.

Meminta izin

Untuk membaca dari Penyedia Kontak, aplikasi Anda harus memiliki Izin READ_CONTACTS. Untuk meminta izin ini, tambahkan elemen turunan <manifest> berikut 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 tergantung pada tipe datanya. Untuk memastikan Anda mendapatkan semua kolom yang mungkin untuk semua tipe data yang mungkin, Anda perlu menambahkan semua nama kolom pada proyeksi Anda. Selalu ambil Data._ID jika Anda mengaitkan hasil Cursor ke ListView; jika tidak, binding tidak akan berfungsi. Ambil juga Data.MIMETYPE agar Anda dapat mengidentifikasi jenis data dari setiap baris yang Anda ambil. 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 sebuah baris pada Tabel ContactsContract.Data, menggunakan nama kolom yang ditentukan di class ContactsContract.Data.

Atau, Anda juga dapat menggunakan konstanta kolom lain yang ditentukan di atau diwarisi oleh class ContactsContract.Data. Namun, perhatikan bahwa kolom SYNC1 sampai SYNC4 dimaksudkan untuk digunakan oleh sinkronisasi adaptor, sehingga datanya tidak berguna.

Menentukan kriteria pemilihan

Tentukan konstanta untuk klausa pemilihan, array untuk menampung argumen pemilihan, dan variabel untuk menampung nilai pemilihan. 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 Anda memastikan bahwa hasil penelusuran dihasilkan dengan binding, bukan kompilasi SQL. Pendekatan ini menghilangkan kemungkinan injeksi SQL berbahaya.

Menentukan urutan penyortiran

Tetapkan urutan penyortiran yang Anda inginkan dalam Cursor yang dihasilkan. Kepada satukan semua baris untuk tipe data tertentu, urutkan berdasarkan Data.MIMETYPE. Argumen kueri ini mengelompokkan semua baris email menjadi satu, semua baris telepon menjadi satu, dan seterusnya. 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 melalui Cursor yang ditampilkan, menentukan jenis data baris saat ini, dan menyimpan data untuk baris yang menggunakan subjenis. Kapan Anda selesai membaca kursor, Anda kemudian dapat mengurutkan setiap tipe data berdasarkan subtipe dan menampilkan hasil pengujian tersebut.

Menginisialisasi loader

Selalu lakukan pengambilan dari Penyedia Kontak (dan semua penyedia konten lainnya) dalam di thread latar belakang. Gunakan framework Loader yang ditentukan oleh Class LoaderManager dan Antarmuka LoaderManager.LoaderCallbacks untuk mengerjakan latar belakang atau pengambilan.

Setelah siap mengambil baris, lakukan 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 loader di aplikasi sehingga Anda dapat membedakan antara loader satu dengan lainnya.

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()

Implementasikan 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()

Implementasikan 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 menetapkannya ke null. Jika tidak, framework loader tidak akan menghancurkan Cursor lama, dan Anda akan mendapatkan 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

Pengambilan jenis data tertentu untuk kontak, seperti semua email, mengikuti pola yang sama sebagai mengambil semua detail. Ini adalah satu-satunya perubahan yang perlu Anda buat pada kode yang tercantum di Mengambil semua detail untuk kontak:

Proyeksi
Ubah proyeksi Anda untuk mengambil kolom-kolom yang spesifik untuk tipe data. Ubah juga proyeksi untuk menggunakan konstanta nama kolom yang didefinisikan dalam Subclass ContactsContract.CommonDataKinds yang sesuai dengan tipe data.
Pemilihan
Modifikasi teks pemilihan untuk mencari Nilai MIMETYPE yang spesifik untuk tipe data Anda.
Tata urutan
Karena Anda hanya memilih satu jenis detail, jangan kelompokkan Cursor yang ditampilkan menurut Data.MIMETYPE.

Modifikasi ini dijelaskan di bagian berikut.

Menentukan proyeksi

Definisikan kolom yang ingin Anda ambil, menggunakan konstanta nama kolom di subclass ContactsContract.CommonDataKinds untuk jenis datanya. Jika Anda ingin mengaitkan Cursor dengan 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 alamat email nama kolom membuat kode lebih mudah dibaca.

Dalam proyeksi ini, Anda juga dapat menggunakan salah satu kolom lain yang ditentukan dalam subclass ContactsContract.CommonDataKinds.

Menentukan kriteria pemilihan

Tentukan ekspresi teks penelusuran yang mengambil baris untuk kontak tertentu LOOKUP_KEY dan Data.MIMETYPE dari detail yang Anda kita inginkan. Sertakan nilai MIMETYPE di tanda kutip tunggal dengan menyambungkan "'" karakter (tanda kutip tunggal) untuk awal dan akhir dari konstanta; jika tidak, penyedia menginterpretasikan konstanta sebagai nama variabel daripada daripada sebagai nilai string. Anda tidak perlu menggunakan {i>placeholder<i} untuk nilai ini, karena Anda menggunakan konstanta daripada nilai yang diberikan 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 sebuah jenis data tertentu, hapus pengurutan berdasarkan MIMETYPE. Sebagai gantinya, jika jenis data detail yang Anda telusuri menyertakan subjenis, lakukan penyortiran menurut subjenis tersebut. Misalnya, untuk data email yang dapat Anda urutkan Email.TYPE:

Kotlin

private const val SORT_ORDER: String = "${Email.TYPE} ASC"

Java

    private static final String SORT_ORDER = Email.TYPE + " ASC ";