Penyedia Kontak adalah komponen Android yang andal dan fleksibel yang mengelola repositori pusat data tentang orang di perangkat. Penyedia Kontak adalah sumber data yang Anda lihat di aplikasi kontak perangkat, dan Anda juga dapat mengakses datanya di aplikasi Anda sendiri serta mentransfer data antara perangkat dan layanan online. Penyedia mengakomodasi berbagai sumber data dan mencoba mengelola sebanyak mungkin data untuk setiap orang, sehingga organisasinya menjadi kompleks. Oleh karena itu, API penyedia mencakup serangkaian class dan antarmuka kontrak yang ekstensif yang memfasilitasi pengambilan dan modifikasi data.
Panduan ini menjelaskan hal-hal berikut:
- Struktur penyedia dasar.
- Cara mengambil data dari penyedia.
- Cara memodifikasi data di penyedia.
- Cara menulis adaptor sinkronisasi untuk menyinkronkan data dari server Anda ke Penyedia Kontak.
Panduan ini beranggapan bahwa Anda mengetahui dasar-dasar penyedia materi Android. Untuk mempelajari lebih lanjut penyedia konten Android, baca panduan Dasar-dasar Penyedia Konten.
Organisasi Penyedia Kontak
Penyedia Kontak adalah komponen penyedia konten Android. Aplikasi ini menyimpan tiga jenis data tentang seseorang, yang masing-masing sesuai dengan tabel yang ditawarkan oleh penyedia, seperti yang diilustrasikan dalam gambar 1:

Gambar 1. Struktur tabel Penyedia Kontak.
Ketiga tabel disebut secara umum menurut nama class kontrak. Class menentukan konstanta untuk URI konten, nama kolom, dan nilai kolom yang digunakan oleh tabel:
-
Tabel
ContactsContract.Contacts
- Baris yang merepresentasikan orang yang berbeda, berdasarkan penggabungan baris kontak mentah.
-
Tabel
ContactsContract.RawContacts
- Baris yang berisi ringkasan data seseorang, khusus untuk akun dan jenis pengguna.
-
Tabel
ContactsContract.Data
- Baris yang berisi detail untuk kontak mentah, seperti alamat email atau nomor telepon.
Tabel lain yang diwakili oleh kelas kontrak di ContactsContract
adalah tabel tambahan yang digunakan Penyedia Kontak untuk mengelola operasinya atau mendukung
fungsi tertentu dalam aplikasi kontak atau telepon di perangkat.
Kontak mentah
Kontak mentah merepresentasikan data seseorang yang berasal dari satu jenis akun dan nama akun. Karena Penyedia Kontak memungkinkan lebih dari satu layanan online sebagai sumber data untuk seseorang, Penyedia Kontak memungkinkan beberapa kontak mentah untuk orang yang sama. Beberapa kontak mentah juga memungkinkan pengguna menggabungkan data seseorang dari lebih dari satu akun dari jenis akun yang sama.
Sebagian besar data untuk kontak mentah tidak disimpan dalam
tabel ContactsContract.RawContacts
. Sebagai gantinya, data disimpan dalam satu atau beberapa
baris di tabel ContactsContract.Data
. Setiap baris data memiliki kolom
Data.RAW_CONTACT_ID
yang
berisi nilai RawContacts._ID
dari
baris ContactsContract.RawContacts
induknya.
Kolom-kolom kontak mentah yang penting
Kolom penting dalam tabel ContactsContract.RawContacts
tercantum dalam tabel 1. Bacalah catatan yang diberikan setelah tabel:
Tabel 1. Kolom-kolom kontak mentah yang penting.
Nama kolom | Gunakan | Catatan |
---|---|---|
ACCOUNT_NAME
|
Nama akun untuk jenis akun yang menjadi sumber kontak mentah ini.
Misalnya, nama akun Akun Google adalah salah satu alamat Gmail pemilik perangkat. Lihat entri berikutnya untuk
ACCOUNT_TYPE untuk mengetahui
informasi selengkapnya.
|
Format nama ini khusus untuk tipe akun ini. Tidak harus berupa alamat email. |
ACCOUNT_TYPE
|
Jenis akun yang menjadi sumber kontak mentah ini. Misalnya, jenis akun Akun Google adalah com.google . Selalu tetapkan jenis akun Anda
dengan ID domain untuk domain yang Anda miliki atau kontrol. Tindakan ini akan memastikan jenis akun Anda unik.
|
Jenis akun yang menawarkan data kontak biasanya memiliki adaptor sinkronisasi terkait yang disinkronkan dengan Penyedia Kontak. |
DELETED
|
Bendera "dihapus" untuk kontak mentah. | Flag ini memungkinkan Penyedia Kontak mempertahankan baris secara internal hingga adaptor sinkronisasi dapat menghapus baris dari servernya, lalu akhirnya menghapus baris dari repositori. |
Catatan
Berikut adalah catatan penting tentang tabel
ContactsContract.RawContacts
:
-
Nama kontak mentah tidak disimpan di barisnya dalam
ContactsContract.RawContacts
. Sebagai gantinya, data tersebut disimpan di tabelContactsContract.Data
, dalam barisContactsContract.CommonDataKinds.StructuredName
. Kontak mentah hanya memiliki satu baris jenis ini dalam tabelContactsContract.Data
. -
Perhatian: Untuk menggunakan data akun Anda sendiri dalam baris kontak mentah, data tersebut harus
didaftarkan terlebih dahulu dengan
AccountManager
. Untuk melakukannya, minta pengguna menambahkan jenis akun dan nama akun mereka ke daftar akun. Jika Anda tidak melakukannya, Penyedia Kontak akan otomatis menghapus baris kontak mentah Anda.Misalnya, jika Anda ingin aplikasi mempertahankan data kontak untuk layanan berbasis web dengan domain
com.example.dataservice
, dan akun pengguna untuk layanan Anda adalahbecky.sharp@dataservice.example.com
, pengguna harus terlebih dahulu menambahkan "jenis" akun (com.example.dataservice
) dan "nama" akun (becky.smart@dataservice.example.com
) sebelum aplikasi Anda dapat menambahkan baris kontak mentah. Anda dapat menjelaskan persyaratan ini kepada pengguna dalam dokumentasi, atau Anda dapat meminta pengguna untuk menambahkan jenis dan nama, atau keduanya. Jenis akun dan nama akun dijelaskan secara lebih mendetail di bagian berikutnya.
Sumber data kontak mentah
Untuk memahami cara kerja kontak mentah, pertimbangkan pengguna "Emily Dickinson" yang memiliki tiga akun pengguna berikut yang ditentukan di perangkatnya:
emily.dickinson@gmail.com
emilyd@gmail.com
- Akun Twitter "belle_of_amherst"
Pengguna ini telah mengaktifkan Sinkronkan Kontak untuk ketiga akun ini di setelan Akun.
Misalkan Emily Dickinson membuka jendela browser, login ke Gmail sebagai
emily.dickinson@gmail.com
, membuka
Kontak, dan menambahkan "Thomas Higginson". Kemudian, dia login ke Gmail sebagai
emilyd@gmail.com
dan mengirim email ke "Thomas Higginson", yang secara otomatis
menambahkannya sebagai kontak. Dia juga mengikuti "colonel_tom" (ID Twitter Thomas Higginson) di
Twitter.
Penyedia Kontak membuat tiga kontak mentah akibat pekerjaan ini:
-
Kontak mentah untuk "Thomas Higginson" yang terkait dengan
emily.dickinson@gmail.com
. Tipe akun penggunanya adalah Google. -
Kontak mentah kedua untuk "Thomas Higginson" yang terkait dengan
emilyd@gmail.com
. Tipe akun pengguna juga Google. Ada kontak mentah kedua meskipun namanya sama dengan nama sebelumnya, karena orang tersebut ditambahkan untuk akun pengguna yang berbeda. - Kontak mentah ketiga untuk "Thomas Higginson" yang terkait dengan "belle_of_amherst". Jenis akun pengguna adalah Twitter.
Data
Seperti yang disebutkan sebelumnya, data untuk kontak mentah disimpan dalam
baris ContactsContract.Data
yang ditautkan ke nilai
_ID
kontak mentah. Hal ini memungkinkan satu kontak mentah memiliki beberapa instance dari jenis data yang sama seperti alamat email atau nomor telepon. Misalnya, jika
"Thomas Higginson" untuk emilyd@gmail.com
(baris kontak mentah untuk Thomas Higginson
yang terkait dengan Akun Google emilyd@gmail.com
) memiliki alamat email rumah
thigg@gmail.com
dan alamat email kantor
thomas.higginson@gmail.com
, Penyedia Kontak menyimpan dua baris alamat email
dan menautkannya ke kontak mentah.
Perhatikan bahwa tipe data yang berbeda disimpan dalam satu tabel ini. Nama tampilan,
nomor telepon, email, alamat pos, foto, dan baris detail situs semuanya ada di
tabel ContactsContract.Data
. Untuk membantu mengelola hal ini, tabel
ContactsContract.Data
memiliki beberapa kolom dengan nama deskriptif,
dan kolom lainnya dengan nama umum. Isi kolom nama deskriptif memiliki arti yang sama
terlepas dari jenis data dalam baris, sedangkan isi kolom nama umum memiliki
arti yang berbeda-beda, bergantung pada jenis datanya.
Nama kolom deskriptif
Beberapa contoh nama kolom deskriptif adalah:
-
RAW_CONTACT_ID
-
Nilai kolom
_ID
dari kontak mentah untuk data ini. -
MIMETYPE
-
Jenis data yang disimpan dalam baris ini, dinyatakan sebagai jenis MIME kustom. Penyedia Kontak
menggunakan jenis MIME yang ditentukan dalam subclass
ContactsContract.CommonDataKinds
. Jenis MIME ini bersifat open source, dan dapat digunakan oleh aplikasi atau adaptor sinkronisasi apa pun yang berfungsi dengan Penyedia Kontak. -
IS_PRIMARY
-
Jika jenis baris data ini dapat muncul lebih dari sekali untuk kontak mentah, kolom
IS_PRIMARY
menandai baris data yang berisi data utama untuk jenis tersebut. Misalnya, jika pengguna menekan lama nomor telepon kontak dan memilih Tetapkan sebagai default, maka barisContactsContract.Data
yang berisi nomor tersebut akan memiliki kolomIS_PRIMARY
yang ditetapkan ke nilai bukan nol.
Nama kolom generik
Ada 15 kolom generik bernama DATA1
hingga
DATA15
yang tersedia secara umum dan empat kolom generik
tambahan SYNC1
hingga SYNC4
yang hanya boleh digunakan oleh
adaptor sinkronisasi. Konstanta nama kolom generik selalu berfungsi, terlepas dari jenis
data yang ada di baris.
Kolom DATA1
diindeks. Penyedia Kontak selalu menggunakan kolom ini untuk
data yang diharapkan penyedia akan menjadi target kueri yang paling sering. Misalnya,
di baris email, kolom ini berisi alamat email yang sebenarnya.
Menurut konvensi, kolom DATA15
dicadangkan untuk menyimpan data Binary Large Object
(BLOB) seperti thumbnail foto.
Nama kolom bertipe spesifik
Untuk mempermudah penggunaan kolom untuk jenis baris tertentu, Penyedia Kontak
juga menyediakan konstanta nama kolom khusus jenis, yang ditentukan dalam subclass
ContactsContract.CommonDataKinds
. Konstanta hanya memberikan
nama konstanta yang berbeda untuk nama kolom yang sama, yang membantu Anda mengakses data dalam baris
jenis tertentu.
Misalnya, class ContactsContract.CommonDataKinds.Email
menentukan
konstanta nama kolom khusus jenis untuk baris ContactsContract.Data
yang memiliki jenis MIME
Email.CONTENT_ITEM_TYPE
. Class berisi konstanta
ADDRESS
untuk kolom
alamat email. Nilai sebenarnya dari
ADDRESS
adalah "data1", yang
sama dengan nama generik kolom.
Perhatian: Jangan tambahkan data kustom Anda sendiri ke tabel
ContactsContract.Data
menggunakan baris yang memiliki salah satu jenis MIME yang telah ditentukan sebelumnya oleh penyedia. Jika Anda melakukannya, Anda dapat kehilangan data atau menyebabkan penyedia
berfungsi tidak normal. Misalnya, Anda tidak boleh menambahkan baris dengan jenis MIME
Email.CONTENT_ITEM_TYPE
yang berisi nama pengguna, bukan alamat email di
kolom DATA1
. Jika Anda menggunakan jenis MIME kustom Anda sendiri untuk baris, Anda bebas
menentukan nama kolom khusus jenis Anda sendiri dan menggunakan kolom tersebut sesuai keinginan Anda.
Gambar 2 menunjukkan tampilan kolom deskriptif dan kolom data dalam baris ContactsContract.Data
, dan cara nama kolom spesifik per jenis "melapisi" nama kolom generik

Gambar 2. Nama kolom bertipe spesifik dan nama kolom generik.
Kelas nama kolom bertipe spesifik
Tabel 2 berisi daftar kelas nama kolom bertipe spesifik yang paling umum digunakan:
Tabel 2. Kelas nama kolom bertipe spesifik
Kelas pemetaan | Tipe data | Catatan |
---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
Data nama untuk kontak mentah yang dikaitkan dengan baris data ini. | Kontak mentah hanya memiliki salah satu baris ini. |
ContactsContract.CommonDataKinds.Photo |
Foto utama untuk kontak mentah yang dikaitkan dengan baris data ini. | Kontak mentah hanya memiliki salah satu baris ini. |
ContactsContract.CommonDataKinds.Email |
Alamat email untuk kontak mentah yang dikaitkan dengan baris data ini. | Kontak mentah bisa memiliki beberapa alamat email. |
ContactsContract.CommonDataKinds.StructuredPostal |
Alamat pos untuk kontak mentah yang dikaitkan dengan baris data ini. | Kontak mentah bisa memiliki beberapa alamat pos. |
ContactsContract.CommonDataKinds.GroupMembership |
ID yang menautkan kontak mentah ke salah satu grup dalam Penyedia Kontak. | Grup adalah fitur opsional pada tipe akun dan nama akun. Grup kontak dijelaskan secara lebih mendetail di bagian Grup kontak. |
Kontak
Penyedia Kontak menggabungkan baris kontak mentah di semua jenis akun dan nama akun untuk membentuk kontak. Hal ini mempermudah menampilkan dan mengubah semua data yang telah dikumpulkan pengguna untuk seseorang. Penyedia Kontak mengelola pembuatan baris kontak baru, dan penggabungan kontak mentah dengan baris kontak yang ada. Aplikasi maupun adaptor sinkronisasi tidak diizinkan untuk menambahkan kontak, dan beberapa kolom dalam baris kontak bersifat hanya baca.
Catatan: Jika Anda mencoba menambahkan kontak ke Penyedia Kontak dengan
insert()
, Anda akan mendapatkan
pengecualian UnsupportedOperationException
. Jika Anda mencoba memperbarui kolom yang tercantum sebagai "hanya baca", pembaruan akan diabaikan.
Penyedia Kontak membuat kontak baru sebagai respons terhadap penambahan kontak mentah baru yang tidak cocok dengan kontak yang ada. Penyedia juga melakukan hal ini jika data kontak mentah yang ada berubah sedemikian rupa sehingga tidak lagi cocok dengan kontak yang sebelumnya dilampirkan. Jika aplikasi atau adaptor sinkronisasi membuat kontak mentah baru yang tidak cocok dengan kontak yang ada, kontak mentah baru akan digabungkan ke kontak yang ada.
Penyedia Kontak menautkan baris kontak ke baris kontak mentahnya dengan kolom
_ID
baris kontak di tabel Contacts
. Kolom CONTACT_ID
tabel kontak mentah
ContactsContract.RawContacts
berisi nilai _ID
untuk
baris kontak yang terkait dengan setiap baris kontak mentah.
Tabel ContactsContract.Contacts
juga memiliki kolom
LOOKUP_KEY
yang merupakan
link "permanen" ke baris kontak. Karena Penyedia Kontak mempertahankan kontak secara otomatis, Penyedia Kontak dapat mengubah nilai _ID
baris kontak sebagai respons terhadap penggabungan atau sinkronisasi. Meskipun hal ini terjadi, URI konten
CONTENT_LOOKUP_URI
yang dikombinasikan dengan
LOOKUP_KEY
kontak akan tetap
menunjuk ke baris kontak, sehingga Anda dapat menggunakan
LOOKUP_KEY
untuk mempertahankan link ke kontak "favorit", dan sebagainya. Kolom ini memiliki formatnya sendiri yang
tidak terkait dengan format kolom _ID
.
Gambar 3 menampilkan cara ketiga tabel utama terkait satu sama lain.

Gambar 3. Hubungan tabel Contacts, Raw Contacts, dan Details.
Perhatian: Jika Anda memublikasikan aplikasi ke Google Play Store, atau jika aplikasi Anda ada di perangkat yang menjalankan Android 10 (level API 29) atau yang lebih tinggi, perlu diingat bahwa serangkaian terbatas kolom dan metode data kontak tidak digunakan lagi.
Dalam kondisi yang disebutkan, sistem secara berkala menghapus nilai apa pun yang ditulis ke kolom data ini:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
API yang digunakan untuk mengatur kolom data di atas juga sudah tidak digunakan lagi.
Selain itu, kolom berikut tidak lagi sering menampilkan kontak. Perhatikan bahwa beberapa kolom ini memengaruhi peringkat kontak hanya jika kontak adalah bagian dari jenis data tertentu.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(hanya memengaruhi Email, Telepon, Dapat Dihubungi, dan Dapat Dihubungi jenis data) -
ENTERPRISE_CONTENT_FILTER_URI
(hanya memengaruhi jenis data Email, Telepon, dan Dapat Dipanggil)
Jika aplikasi Anda mengakses atau memperbarui kolom atau API ini, gunakan metode alternatif. Misalnya, Anda dapat memenuhi kasus penggunaan tertentu dengan menggunakan penyedia konten pribadi atau data lain yang disimpan dalam aplikasi atau sistem backend Anda.
Untuk memverifikasi bahwa fungsi aplikasi Anda tidak terpengaruh oleh perubahan ini, Anda dapat menghapus kolom data ini secara manual. Untuk melakukannya, jalankan perintah ADB berikut di perangkat yang menjalankan Android 4.1 (API level 16) atau yang lebih tinggi:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
Data Dari adaptor sinkronisasi
Pengguna memasukkan data kontak langsung ke perangkat, tetapi data juga mengalir ke Penyedia Kontak dari layanan web melalui adaptor sinkronisasi, yang mengotomatiskan transfer data antara perangkat dan layanan. Adaptor sinkronisasi berjalan di latar belakang
di bawah kontrol sistem, dan memanggil metode ContentResolver
untuk mengelola data.
Di Android, layanan web yang digunakan adaptor sinkronisasi diidentifikasi melalui tipe akun. Setiap adaptor sinkronisasi berfungsi dengan satu jenis akun, tetapi dapat mendukung beberapa nama akun untuk jenis tersebut. Jenis akun dan nama akun dijelaskan secara singkat di bagian Sumber data kontak mentah. Definisi berikut menawarkan detail selengkapnya, dan menjelaskan hubungan antara jenis dan nama akun dengan adaptor dan layanan sinkronisasi.
- Jenis akun
-
Mengidentifikasi layanan tempat pengguna telah menyimpan data. Sebagian besar waktu, pengguna harus
melakukan autentikasi dengan layanan. Misalnya, Google Kontak adalah jenis akun, yang diidentifikasi
oleh kode
google.com
. Nilai ini sesuai dengan jenis akun yang digunakan olehAccountManager
. - Nama akun
- Mengidentifikasi akun atau login tertentu untuk jenis akun. Akun Google Kontak sama dengan Akun Google, yang memiliki alamat email sebagai nama akun. Layanan lain mungkin menggunakan nama pengguna satu-kata atau identitas berupa angka.
Jenis akun tidak harus unik. Pengguna dapat mengonfigurasi beberapa akun Google Kontak dan mendownload datanya ke Penyedia Kontak; hal ini dapat terjadi jika pengguna memiliki satu set kontak pribadi untuk nama akun pribadi, dan set lainnya untuk akun kerja. Nama akun biasanya unik. Bersama-sama, keduanya mengidentifikasi alur data tertentu antara Penyedia Kontak dan layanan eksternal.
Jika ingin mentransfer data layanan ke Penyedia Kontak, Anda harus menulis adaptor sinkronisasi sendiri. Hal ini dijelaskan lebih detail di bagian Adaptor sinkronisasi Penyedia Kontak.
Gambar 4 menunjukkan cara Penyedia Kontak sesuai dengan alur data tentang orang. Di kotak yang ditandai "adaptor sinkronisasi", setiap adaptor diberi label berdasarkan jenis akunnya.

Gambar 4. Aliran data Penyedia Kontak.
Izin yang diperlukan
Aplikasi yang ingin mengakses Penyedia Kontak harus meminta izin berikut:
- Akses baca ke satu atau beberapa tabel
-
READ_CONTACTS
, yang ditentukan dalamAndroidManifest.xml
dengan elemen<uses-permission>
sebagai<uses-permission android:name="android.permission.READ_CONTACTS">
. - Akses tulis ke satu atau beberapa tabel
-
WRITE_CONTACTS
, yang ditentukan dalamAndroidManifest.xml
dengan elemen<uses-permission>
sebagai<uses-permission android:name="android.permission.WRITE_CONTACTS">
.
Izin ini tidak diperluas ke data profil pengguna. Profil pengguna dan izin yang diperlukan dibahas di bagian berikut, Profil pengguna.
Ingatlah bahwa data kontak pengguna bersifat pribadi dan sensitif. Pengguna khawatir tentang privasi mereka, sehingga mereka tidak ingin aplikasi mengumpulkan data tentang mereka atau kontak mereka. Jika tidak jelas mengapa Anda memerlukan izin untuk mengakses data kontak mereka, mereka dapat memberikan rating rendah pada aplikasi Anda atau menolak untuk menginstalnya.
Profil pengguna
Tabel ContactsContract.Contacts
memiliki satu baris yang berisi
data profil untuk pengguna perangkat. Data ini menjelaskan user
perangkat, bukan salah satu kontak pengguna. Baris kontak profil ditautkan ke baris kontak mentah untuk setiap sistem yang menggunakan profil.
Setiap baris kontak mentah profil bisa memiliki beberapa baris data. Konstanta untuk mengakses profil
pengguna tersedia di class ContactsContract.Profile
.
Akses ke profil pengguna memerlukan izin khusus. Selain izin
READ_CONTACTS
dan
WRITE_CONTACTS
yang diperlukan untuk membaca dan menulis, akses
ke profil pengguna memerlukan izin android.Manifest.permission#READ_PROFILE dan
android.Manifest.permission#WRITE_PROFILE untuk akses baca dan tulis,
masing-masing.
Ingatlah bahwa Anda harus menganggap profil pengguna sebagai sensitif. Izin android.Manifest.permission#READ_PROFILE memungkinkan Anda mengakses data pengguna perangkat yang dapat mengidentifikasi pribadi. Pastikan untuk memberi tahu pengguna alasan Anda memerlukan izin akses profil pengguna dalam deskripsi aplikasi Anda.
Untuk mengambil baris kontak yang berisi profil pengguna, panggil ContentResolver.query()
. Setel URI konten ke
CONTENT_URI
dan jangan berikan
kriteria pemilihan apa pun. Anda juga dapat menggunakan URI konten ini sebagai URI dasar untuk mengambil kontak mentah atau data untuk profil. Misalnya, cuplikan kode ini mengambil data untuk profil:
Kotlin
// Sets the columns to retrieve for the user profile projection = arrayOf( ContactsContract.Profile._ID, ContactsContract.Profile.DISPLAY_NAME_PRIMARY, ContactsContract.Profile.LOOKUP_KEY, ContactsContract.Profile.PHOTO_THUMBNAIL_URI ) // Retrieves the profile from the Contacts Provider profileCursor = contentResolver.query( ContactsContract.Profile.CONTENT_URI, projection, null, null, null )
Java
// Sets the columns to retrieve for the user profile projection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.LOOKUP_KEY, Profile.PHOTO_THUMBNAIL_URI }; // Retrieves the profile from the Contacts Provider profileCursor = getContentResolver().query( Profile.CONTENT_URI, projection , null, null, null);
Catatan: Jika Anda mengambil beberapa baris kontak, dan Anda ingin menentukan apakah salah satunya adalah profil pengguna, uji kolom IS_USER_PROFILE
baris tersebut. Kolom ini
disetel ke "1" jika kontak adalah profil pengguna.
Metadata Penyedia Kontak
Penyedia Kontak mengelola data yang melacak status data kontak di repositori. Metadata tentang repositori ini disimpan di berbagai tempat, termasuk
baris tabel Kontak Mentah, Data, dan Kontak, tabel
ContactsContract.Settings
, dan tabel
ContactsContract.SyncState
. Tabel berikut menunjukkan
efek setiap bagian metadata ini:
Tabel 3. Metadata di Penyedia Kontak
Tabel | Kolom | Nilai | Arti |
---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
"0" - tidak berubah sejak sinkronisasi terakhir. |
Menandai kontak mentah yang diubah di perangkat dan harus disinkronkan kembali ke
server. Nilai ditetapkan secara otomatis oleh Penyedia Kontak saat aplikasi Android
memperbarui baris.
Adaptor sinkronisasi yang mengubah tabel data atau kontak mentah harus selalu menambahkan
string |
"1" - diubah sejak sinkronisasi terakhir, perlu disinkronkan kembali ke server. | |||
ContactsContract.RawContacts |
VERSION |
Nomor versi baris ini. | Penyedia Kontak akan otomatis menaikkan nilai ini setiap kali baris atau data terkaitnya berubah. |
ContactsContract.Data |
DATA_VERSION |
Nomor versi baris ini. | Penyedia Kontak akan otomatis menaikkan nilai ini setiap kali baris data diubah. |
ContactsContract.RawContacts |
SOURCE_ID |
Nilai string yang secara unik mengidentifikasi kontak mentah ini ke akun tempat kontak tersebut dibuat. |
Saat adaptor sinkronisasi membuat kontak mentah baru, kolom ini harus disetel ke
ID unik server untuk kontak mentah. Saat aplikasi Android membuat kontak mentah
baru, aplikasi harus mengosongkan kolom ini. Hal ini memberi sinyal pada adaptor sinkronisasi bahwa adaptor harus membuat kontak mentah baru di server, dan mendapatkan nilai untuk SOURCE_ID .
Khususnya, ID sumber harus unik untuk setiap jenis akun dan harus stabil di seluruh sinkronisasi:
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" - Kontak dalam grup ini tidak boleh terlihat di UI aplikasi Android. | Kolom ini untuk kompatibilitas dengan server yang memungkinkan pengguna menyembunyikan kontak dalam grup tertentu. |
"1" - Kontak dalam grup ini diizinkan untuk terlihat di UI aplikasi. | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" - Untuk akun dan jenis akun ini, kontak yang bukan milik grup tidak terlihat oleh UI aplikasi Android. |
Secara default, kontak tidak terlihat jika tidak ada kontak mentahnya yang termasuk dalam grup
(Keanggotaan grup untuk kontak mentah ditunjukkan oleh satu atau beberapa
baris ContactsContract.CommonDataKinds.GroupMembership
dalam tabel ContactsContract.Data ).
Dengan menyetel tanda ini di baris tabel ContactsContract.Settings
untuk jenis akun dan akun, Anda dapat memaksa kontak tanpa grup agar terlihat.
Salah satu penggunaan tanda ini adalah untuk menampilkan kontak dari server yang tidak menggunakan grup.
|
"1" - Untuk akun dan jenis akun ini, kontak yang tidak termasuk dalam grup dapat dilihat oleh UI aplikasi. | |||
ContactsContract.SyncState |
(semua) | Gunakan tabel ini untuk menyimpan metadata bagi adaptor sinkronisasi Anda. | Dengan tabel ini, Anda dapat menyimpan status sinkronisasi dan data terkait sinkronisasi lainnya secara persisten di perangkat. |
Akses Penyedia Kontak
Bagian ini menjelaskan panduan untuk mengakses data dari Penyedia Kontak, dengan berfokus pada hal berikut:
- Kueri entitas.
- Modifikasi batch.
- Pengambilan dan modifikasi dengan maksud.
- Integritas data.
Melakukan modifikasi dari adaptor sinkronisasi juga dibahas lebih detail di bagian Adaptor sinkronisasi Penyedia Kontak.
Membuat kueri entitas
Karena tabel Penyedia Kontak disusun dalam hierarki, sering kali berguna untuk
mengambil baris dan semua baris "turunan" yang ditautkan ke baris tersebut. Misalnya, untuk menampilkan
semua informasi seseorang, Anda mungkin ingin mengambil semua
baris ContactsContract.RawContacts
untuk satu
baris ContactsContract.Contacts
, atau semua
baris ContactsContract.CommonDataKinds.Email
untuk satu
baris ContactsContract.RawContacts
. Untuk memfasilitasi hal ini, Penyedia Kontak menawarkan konstruksi entitas, yang bertindak seperti gabungan database antar-tabel.
Entitas adalah seperti tabel yang terdiri atas kolom-kolom terpilih dari tabel induk dan tabel turunannya.
Saat membuat kueri entity, Anda memberikan proyeksi dan kriteria penelusuran berdasarkan kolom
yang tersedia dari entity. Hasilnya adalah Cursor
yang berisi
satu baris untuk setiap baris tabel turunan yang diambil. Misalnya, jika Anda membuat kueri
ContactsContract.Contacts.Entity
untuk nama kontak
dan semua baris ContactsContract.CommonDataKinds.Email
untuk semua
kontak mentah untuk nama tersebut, Anda akan mendapatkan Cursor
yang berisi satu baris
untuk setiap baris ContactsContract.CommonDataKinds.Email
.
Entitas menyederhanakan kueri. Dengan menggunakan entitas, Anda dapat mengambil semua data kontak untuk kontak atau kontak mentah sekaligus, alih-alih harus mengkueri tabel induk terlebih dahulu untuk mendapatkan ID, lalu harus mengkueri tabel turunan dengan ID tersebut. Selain itu, Penyedia Kontak memproses kueri terhadap entitas dalam satu transaksi, yang memastikan bahwa data yang diambil konsisten secara internal.
Catatan: Entitas biasanya tidak berisi semua kolom tabel induk dan
turunan. Jika Anda mencoba menggunakan nama kolom yang tidak ada dalam daftar konstanta nama kolom
untuk entitas, Anda akan mendapatkan Exception
.
Cuplikan berikut menampilkan cara mengambil semua baris kontak mentah untuk sebuah kontak. Cuplikan
adalah bagian dari aplikasi yang lebih besar yang memiliki dua aktivitas, "main" dan "detail". Aktivitas utama
menampilkan daftar baris kontak; saat pengguna memilih salah satunya, aktivitas akan mengirimkan ID-nya ke aktivitas
detail. Aktivitas detail menggunakan ContactsContract.Contacts.Entity
untuk menampilkan semua baris data dari semua kontak mentah yang terkait dengan kontak yang dipilih.
Cuplikan ini diambil dari aktivitas "detail":
Kotlin
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY ) // Initializes the loader identified by LOADER_ID. loaderManager.initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this // The context of the activity ) // Creates a new cursor adapter to attach to the list view cursorAdapter = SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0) // flags // Sets the ListView's backing adapter. rawContactList.adapter = cursorAdapter ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ val projection: Array<String> = arrayOf( ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE ) /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC" /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return CursorLoader( applicationContext, // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder // Sort by the raw contact ID. ) }
Java
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by LOADER_ID. getLoaderManager().initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this); // The context of the activity // Creates a new cursor adapter to attach to the list view cursorAdapter = new SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0); // flags // Sets the ListView's backing adapter. rawContactList.setAdapter(cursorAdapter); ... @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ String[] projection = { ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE }; /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC"; /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return new CursorLoader( getApplicationContext(), // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }
Setelah pemuatan selesai, LoaderManager
akan memanggil callback ke
onLoadFinished()
. Salah satu argumen masuk ke metode ini adalah
Cursor
dengan hasil kueri. Di aplikasi Anda sendiri, Anda bisa mendapatkan
data dari Cursor
ini untuk menampilkannya atau menggunakannya lebih lanjut.
Modifikasi batch
Jika memungkinkan, Anda harus menyisipkan, memperbarui, dan menghapus data di Penyedia Kontak dalam
"mode batch", dengan membuat ArrayList
dari
objek ContentProviderOperation
dan memanggil
applyBatch()
. Karena
Penyedia Kontak melakukan semua operasi dalam
applyBatch()
dalam satu
transaksi, modifikasi Anda tidak akan pernah meninggalkan repositori kontak dalam keadaan
yang tidak konsisten. Modifikasi batch juga memfasilitasi penyisipan kontak mentah dan data detailnya secara bersamaan.
Catatan: Untuk mengubah kontak mentah tunggal, pertimbangkan untuk mengirim intent ke aplikasi kontak perangkat, bukan menangani modifikasi di aplikasi Anda. Tindakan ini dijelaskan lebih mendetail di bagian Pengambilan dan modifikasi dengan intent.
Yield point
Modifikasi batch yang berisi banyak operasi dapat memblokir proses lain,
sehingga menghasilkan pengalaman pengguna yang buruk secara keseluruhan. Untuk mengatur semua modifikasi yang ingin Anda
lakukan dalam sesedikit mungkin daftar terpisah, dan sekaligus mencegahnya
memblokir sistem, Anda harus menetapkan titik hasil untuk satu atau beberapa operasi.
Titik hasil adalah objek ContentProviderOperation
yang nilai
isYieldAllowed()
-nya ditetapkan ke
true
. Saat menemukan titik hasil, Penyedia Kontak akan menjeda pekerjaannya untuk
membiarkan proses lain berjalan dan menutup transaksi saat ini. Saat penyedia dimulai lagi, penyedia
akan melanjutkan dengan operasi berikutnya di ArrayList
dan memulai
transaksi baru.
Poin hasil menghasilkan lebih dari satu transaksi per panggilan ke
applyBatch()
. Karena
itu, Anda harus menetapkan titik hasil untuk operasi terakhir untuk sekumpulan baris terkait.
Misalnya, Anda harus menetapkan titik hasil untuk operasi terakhir dalam serangkaian operasi yang menambahkan
baris kontak mentah dan baris data terkaitnya, atau operasi terakhir untuk serangkaian baris yang terkait
dengan satu kontak.
Yield point juga merupakan unit operasi atomis. Semua akses di antara dua titik hasil akan berhasil atau gagal sebagai satu unit. Jika Anda tidak menetapkan titik hasil apa pun, operasi atomik terkecil adalah seluruh batch operasi. Jika Anda menggunakan titik hasil, Anda mencegah operasi menurunkan performa sistem, sekaligus memastikan bahwa subset operasi bersifat atomik.
Acuan balik modifikasi
Saat menyisipkan baris kontak mentah baru dan baris data terkaitnya sebagai sekumpulan objek ContentProviderOperation
, Anda harus menautkan baris data ke baris kontak mentah dengan menyisipkan nilai _ID
kontak mentah sebagai nilai RAW_CONTACT_ID
. Namun, nilai ini tidak tersedia saat Anda membuat ContentProviderOperation
untuk baris data, karena Anda belum menerapkan ContentProviderOperation
untuk baris kontak mentah. Untuk mengatasi masalah ini,
class ContentProviderOperation.Builder
memiliki metode
withValueBackReference()
.
Metode ini memungkinkan Anda menyisipkan atau mengubah kolom dengan
hasil operasi sebelumnya.
Metode withValueBackReference()
memiliki dua argumen:
-
key
- Kunci pasangan nilai kunci. Nilai argumen ini harus berupa nama kolom dalam tabel yang Anda ubah.
-
previousResult
-
Indeks berbasis 0 dari nilai dalam array objek
ContentProviderResult
dariapplyBatch()
. Saat operasi batch diterapkan, hasil setiap operasi disimpan dalam array hasil sementara. NilaipreviousResult
adalah indeks salah satu hasil ini, yang diambil dan disimpan dengan nilaikey
. Hal ini memungkinkan Anda menyisipkan rekaman kontak mentah baru dan mendapatkan kembali nilai_ID
-nya, lalu membuat "referensi kembali" ke nilai saat Anda menambahkan barisContactsContract.Data
.Seluruh array hasil dibuat saat Anda pertama kali memanggil
applyBatch()
, dengan ukuran yang sama dengan ukuranArrayList
dari objekContentProviderOperation
yang Anda berikan. Namun, semua elemen dalam array hasil ditetapkan kenull
, dan jika Anda mencoba melakukan referensi kembali ke hasil untuk operasi yang belum diterapkan,withValueBackReference()
akan memunculkanException
.
Cuplikan kode berikut menampilkan cara menyisipkan kontak mentah baru dan data secara batch. Mereka mencakup kode yang menetapkan titik hasil dan menggunakan referensi kembali.
Cuplikan pertama mengambil data kontak dari UI. Pada tahap ini, pengguna telah memilih akun yang akan ditambahi kontak mentah baru.
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
Cuplikan berikutnya membuat operasi untuk menyisipkan baris kontak mentah ke dalam
tabel ContactsContract.RawContacts
:
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
Berikutnya, kode akan membuat baris data untuk baris-baris nama tampilan, ponsel, dan email.
Setiap objek builder operasi menggunakan
withValueBackReference()
untuk mendapatkan
RAW_CONTACT_ID
. Titik referensi
kembali ke objek ContentProviderResult
dari operasi pertama,
yang menambahkan baris kontak mentah dan menampilkan nilai _ID
barunya. Akibatnya, setiap baris data akan otomatis ditautkan berdasarkan
RAW_CONTACT_ID
ke baris ContactsContract.RawContacts
baru yang menjadi bagiannya.
Objek ContentProviderOperation.Builder
yang menambahkan baris email
ditandai dengan withYieldAllowed()
, yang menetapkan titik hasil:
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
Cuplikan terakhir menunjukkan panggilan ke
applyBatch()
yang
menyisipkan baris data dan kontak mentah baru.
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
Operasi batch juga memungkinkan Anda menerapkan kontrol serentak yang optimis, metode penerapan transaksi modifikasi tanpa harus mengunci repositori pokok. Untuk menggunakan metode ini, Anda menerapkan transaksi, lalu memeriksa modifikasi lain yang mungkin telah dilakukan pada saat yang sama. Jika Anda menemukan modifikasi yang tidak konsisten telah terjadi, Anda dapat meng-roll back transaksi dan mencobanya lagi.
Kontrol konkurensi optimis berguna untuk perangkat seluler, yang hanya memiliki satu pengguna dalam satu waktu, dan akses simultan ke repositori data jarang terjadi. Karena penguncian tidak digunakan, tidak ada waktu yang terbuang untuk menyetel kunci atau menunggu transaksi lain melepas kuncinya.
Untuk menggunakan kontrol konkurensi optimis saat memperbarui satu baris
ContactsContract.RawContacts
, ikuti langkah-langkah berikut:
-
Ambil kolom
VERSION
kontak mentah beserta data lain yang Anda ambil. -
Buat objek
ContentProviderOperation.Builder
yang sesuai untuk menerapkan batasan, menggunakan metodenewAssertQuery(Uri)
. Untuk URI konten, gunakanRawContacts.CONTENT_URI
dengan_ID
kontak mentah yang ditambahkan ke URI tersebut. -
Untuk objek
ContentProviderOperation.Builder
, panggilwithValue()
untuk membandingkan kolomVERSION
dengan nomor versi yang baru saja Anda ambil. -
Untuk
ContentProviderOperation.Builder
yang sama, panggilwithExpectedCount()
untuk memastikan hanya satu baris yang diuji oleh pernyataan ini. -
Panggil
build()
untuk membuat objekContentProviderOperation
, lalu tambahkan objek ini sebagai objek pertama dalamArrayList
yang Anda teruskan keapplyBatch()
. - Terapkan transaksi batch.
Jika baris kontak mentah diperbarui oleh operasi lain antara waktu Anda membaca baris dan
waktu Anda mencoba mengubahnya, ContentProviderOperation
"assert"
akan gagal, dan seluruh batch operasi akan dibatalkan. Kemudian, Anda dapat memilih untuk mencoba lagi batch atau melakukan tindakan lain.
Cuplikan berikut menunjukkan cara membuat "assert"
ContentProviderOperation
setelah membuat kueri untuk satu kontak mentah menggunakan
CursorLoader
:
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
Pengambilan dan modifikasi dengan intent
Mengirim intent ke aplikasi kontak perangkat memungkinkan Anda mengakses Penyedia Kontak secara tidak langsung. Intent ini memulai UI aplikasi kontak perangkat, tempat pengguna dapat melakukan pekerjaan terkait kontak. Dengan tipe akses ini, pengguna bisa:
- Memilih kontak dari daftar dan meneruskannya ke aplikasi untuk pekerjaan lebih jauh.
- Mengedit data kontak yang ada.
- Memasukkan kontak mentah baru untuk akun mereka.
- Menghapus kontak atau data kontak.
Jika pengguna memasukkan atau memperbarui data, Anda dapat mengumpulkan data terlebih dahulu dan mengirimkannya sebagai bagian dari intent.
Saat menggunakan intent untuk mengakses Penyedia Kontak melalui aplikasi kontak perangkat, Anda tidak perlu menulis UI atau kode Anda sendiri untuk mengakses penyedia. Anda juga tidak perlu meminta izin untuk membaca atau menulis ke penyedia. Aplikasi kontak perangkat dapat mendelegasikan izin baca untuk kontak kepada Anda, dan karena Anda melakukan modifikasi pada penyedia melalui aplikasi lain, Anda tidak harus memiliki izin tulis.
Proses umum mengirimkan maksud untuk mengakses penyedia dijelaskan secara mendetail dalam
Panduan Dasar-Dasar Penyedia Konten di bagian "Akses data melalui maksud". Tindakan,
jenis MIME, dan nilai data yang Anda gunakan untuk tugas yang tersedia diringkas dalam Tabel 4, sedangkan
nilai ekstra yang dapat Anda gunakan dengan
putExtra()
tercantum dalam
dokumentasi referensi untuk ContactsContract.Intents.Insert
:
Tabel 4. Intent Penyedia Kontak.
Tugas | Tindakan | Data | Jenis MIME | Catatan |
---|---|---|---|---|
Memilih kontak dari daftar | ACTION_PICK |
Salah satu dari:
|
Tidak digunakan |
Menampilkan daftar kontak mentah atau daftar data dari kontak mentah, bergantung pada
jenis URI konten yang Anda berikan.
Panggil
|
Menyisipkan kontak mentah baru | Insert.ACTION |
T/A |
RawContacts.CONTENT_TYPE , jenis MIME untuk sekumpulan kontak mentah.
|
Menampilkan layar Tambahkan Kontak aplikasi kontak perangkat. Nilai
ekstra yang Anda tambahkan ke intent akan ditampilkan. Jika dikirim dengan
startActivityForResult() ,
URI konten kontak mentah yang baru ditambahkan akan diteruskan kembali ke metode callback
onActivityResult()
aktivitas Anda dalam argumen Intent , di kolom
"data". Untuk mendapatkan nilai, panggil getData() .
|
Mengedit kontak | ACTION_EDIT |
CONTENT_LOOKUP_URI untuk
kontak. Aktivitas editor akan memungkinkan pengguna mengedit data apa pun yang terkait
dengan kontak ini.
|
Contacts.CONTENT_ITEM_TYPE , satu kontak. |
Menampilkan layar Edit Contact dalam aplikasi kontak. Nilai ekstra yang Anda tambahkan ke intent akan ditampilkan. Saat pengguna mengklik Selesai untuk menyimpan editan, aktivitas Anda akan kembali ke latar depan. |
Menampilkan alat pilih yang juga dapat menambahkan data. | ACTION_INSERT_OR_EDIT |
T/A |
CONTENT_ITEM_TYPE
|
Intent ini selalu menampilkan layar pemilih aplikasi kontak. Pengguna dapat
memilih kontak untuk diedit, atau menambahkan kontak baru. Layar edit atau layar tambahkan
akan muncul, bergantung pada pilihan pengguna, dan data tambahan yang Anda teruskan dalam intent
akan ditampilkan. Jika aplikasi Anda menampilkan data kontak seperti email atau nomor telepon, gunakan intent ini untuk mengizinkan pengguna menambahkan data ke kontak yang ada.
kontak,
Catatan: Tidak perlu mengirim nilai nama dalam ekstra intent ini, karena pengguna selalu memilih nama yang ada atau menambahkan nama baru. Selain itu, jika Anda mengirim nama, dan pengguna memilih untuk melakukan pengeditan, aplikasi kontak akan menampilkan nama yang Anda kirim, menggantikan nilai sebelumnya. Jika pengguna tidak memperhatikan hal ini dan menyimpan hasil edit, nilai lama akan hilang. |
Aplikasi kontak perangkat tidak mengizinkan Anda menghapus kontak mentah atau data apa pun dengan
maksud. Sebagai gantinya, untuk menghapus kontak mentah, gunakan
ContentResolver.delete()
atau ContentProviderOperation.newDelete()
.
Cuplikan berikut menunjukkan cara membuat dan mengirim intent yang menyisipkan kontak dan data mentah baru:
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
Integritas data
Karena repositori kontak berisi data penting dan sensitif yang diharapkan pengguna benar dan terbaru, Penyedia Kontak memiliki aturan yang jelas untuk integritas data. Anda bertanggung jawab untuk mematuhi aturan ini saat Anda mengubah data kontak. Aturan penting tercantum di sini:
-
Selalu tambahkan baris
ContactsContract.CommonDataKinds.StructuredName
untuk setiap barisContactsContract.RawContacts
yang Anda tambahkan. -
Baris
ContactsContract.RawContacts
tanpa barisContactsContract.CommonDataKinds.StructuredName
di tabelContactsContract.Data
dapat menyebabkan masalah selama penggabungan. -
Selalu tautkan baris
ContactsContract.Data
baru ke barisContactsContract.RawContacts
induknya. -
Baris
ContactsContract.Data
yang tidak ditautkan keContactsContract.RawContacts
tidak akan terlihat di aplikasi kontak perangkat, dan dapat menyebabkan masalah pada adapter sinkronisasi. - Ubah data hanya untuk kontak mentah yang Anda miliki.
- Ingatlah bahwa Penyedia Kontak biasanya mengelola data dari beberapa jenis akun/layanan online yang berbeda. Anda harus memastikan bahwa aplikasi Anda hanya mengubah atau menghapus data untuk baris yang menjadi milik Anda, dan hanya menyisipkan data dengan jenis dan nama akun yang Anda kontrol.
-
Selalu gunakan konstanta yang ditentukan dalam
ContactsContract
dan subclass-nya untuk otoritas, URI konten, jalur URI, nama kolom, jenis MIME, dan nilaiTYPE
. - Menggunakan konstanta ini membantu Anda menghindari error. Anda juga akan diberi tahu tentang peringatan kompiler jika ada konstanta yang tidak digunakan lagi.
Baris data khusus
Dengan membuat dan menggunakan jenis MIME kustom sendiri, Anda dapat menyisipkan, mengedit, menghapus, dan mengambil
baris data Anda sendiri dalam tabel ContactsContract.Data
. Baris Anda
dibatasi untuk menggunakan kolom yang ditentukan dalam
ContactsContract.DataColumns
, meskipun Anda dapat memetakan nama kolom spesifik jenis Anda sendiri ke nama kolom default. Di aplikasi kontak perangkat,
data untuk baris Anda ditampilkan, tetapi tidak dapat diedit atau dihapus, dan pengguna tidak dapat menambahkan
data tambahan. Untuk mengizinkan pengguna mengubah baris data kustom, Anda harus menyediakan aktivitas
editor di aplikasi Anda sendiri.
Untuk menampilkan data kustom, berikan file contacts.xml
yang berisi elemen
<ContactsAccountType>
dan satu atau beberapa elemen turunan
<ContactsDataKind>
. Hal ini dijelaskan secara lebih mendetail di bagian
<ContactsDataKind> element
.
Untuk mempelajari lebih lanjut jenis MIME kustom, baca panduan Membuat Penyedia Konten.
Adaptor sinkronisasi Penyedia Kontak
Penyedia Kontak secara khusus dirancang untuk menangani sinkronisasi data kontak antara perangkat dan layanan online. Hal ini memungkinkan pengguna mendownload data yang ada ke perangkat baru dan mengupload data yang ada ke akun baru. Sinkronisasi juga memastikan bahwa pengguna memiliki data terbaru, terlepas dari sumber penambahan dan perubahan. Keuntungan lain dari sinkronisasi adalah data kontak tersedia meskipun perangkat tidak terhubung ke jaringan.
Meskipun Anda dapat menerapkan sinkronisasi dengan berbagai cara, sistem Android menyediakan framework sinkronisasi plug-in yang mengotomatiskan tugas berikut:
- Memeriksa ketersediaan jaringan.
- Menjadwalkan dan menjalankan sinkronisasi, berdasarkan preferensi pengguna.
- Memulai kembali sinkronisasi yang telah berhenti.
Untuk menggunakan kerangka kerja ini, Anda harus menyediakan plugin adaptor sinkronisasi. Setiap adaptor sinkronisasi unik untuk penyedia konten dan layanan, tetapi dapat menangani beberapa nama akun untuk layanan yang sama. Framework juga memungkinkan beberapa adaptor sinkronisasi untuk layanan dan penyedia yang sama.
Class dan file adaptor sinkronisasi
Anda menerapkan adaptor sinkronisasi sebagai subclass
AbstractThreadedSyncAdapter
dan menginstalnya sebagai bagian dari aplikasi
Android. Sistem mempelajari adaptor sinkronisasi dari elemen dalam manifes
aplikasi Anda, dan dari file XML khusus yang ditunjukkan oleh manifes. File XML menentukan
jenis akun untuk layanan online dan otoritas untuk penyedia konten, yang bersama-sama
mengidentifikasi adaptor secara unik. Adaptor sinkronisasi tidak menjadi aktif hingga pengguna menambahkan akun untuk jenis akun adaptor sinkronisasi dan mengaktifkan sinkronisasi untuk penyedia konten yang disinkronkan oleh adaptor sinkronisasi. Pada saat itu, sistem mulai mengelola adaptor,
memanggilnya sesuai kebutuhan untuk menyinkronkan antara penyedia konten dan server.
Catatan: Menggunakan jenis akun sebagai bagian dari identifikasi adaptor sinkronisasi memungkinkan
sistem mendeteksi dan mengelompokkan adaptor sinkronisasi yang mengakses layanan berbeda dari
organisasi yang sama. Misalnya, adaptor sinkronisasi untuk layanan online Google semuanya memiliki
jenis akun com.google
yang sama. Saat pengguna menambahkan Akun Google ke perangkat mereka, semua adaptor sinkronisasi yang diinstal untuk layanan Google akan dicantumkan bersama; setiap adaptor sinkronisasi yang dicantumkan akan disinkronkan dengan penyedia konten yang berbeda di perangkat.
Karena sebagian besar layanan mengharuskan pengguna memverifikasi identitas mereka sebelum mengakses
data, sistem Android menawarkan framework autentikasi yang serupa dengan, dan sering kali
digunakan bersama dengan, framework adaptor sinkronisasi. Framework autentikasi menggunakan
autentikator plug-in yang merupakan subclass dari
AbstractAccountAuthenticator
. Pengautentikasi memverifikasi
identitas pengguna dalam langkah-langkah berikut:
- Mengumpulkan nama pengguna, sandi, atau informasi serupa (kredensial pengguna).
- Mengirimkan kredensial ke layanan
- Memeriksa balasan layanan.
Jika layanan menerima kredensial, pengautentikasi dapat
menyimpan kredensial untuk digunakan nanti. Karena framework pengautentikasi plug-in, AccountManager
dapat memberikan akses ke token autentikasi yang didukung dan dipilih untuk diekspos oleh pengautentikasi, seperti token autentikasi OAuth2.
Meskipun autentikasi tidak diharuskan, sebagian besar layanan kontak menggunakannya. Namun, Anda tidak diwajibkan untuk menggunakan framework autentikasi Android untuk melakukan autentikasi.
Implementasi adaptor sinkronisasi
Untuk menerapkan adaptor sinkronisasi untuk Penyedia Kontak, Anda mulai dengan membuat aplikasi Android yang berisi hal berikut:
-
Komponen
Service
yang merespons permintaan dari sistem untuk mengikat ke adaptor sinkronisasi. -
Saat sistem ingin menjalankan sinkronisasi, sistem akan memanggil metode
onBind()
layanan untuk mendapatkanIBinder
untuk adaptor sinkronisasi. Hal ini memungkinkan sistem melakukan panggilan lintas proses ke metode adaptor. -
Adaptor sinkronisasi sebenarnya, diimplementasikan sebagai subclass konkret dari
AbstractThreadedSyncAdapter
. -
Class ini melakukan tugas mendownload data dari server, mengupload data dari
perangkat, dan menyelesaikan konflik. Pekerjaan utama adaptor
dilakukan dalam metode
onPerformSync()
. Instance class ini harus dibuat sebagai singleton. -
Subclass
Application
. -
Class ini bertindak sebagai factory untuk singleton adaptor sinkronisasi. Gunakan metode
onCreate()
untuk membuat instance adaptor sinkronisasi, dan berikan metode "pengambil" statis untuk menampilkan singleton ke metodeonBind()
layanan adaptor sinkronisasi. -
Opsional: Komponen
Service
yang merespons permintaan dari sistem untuk autentikasi pengguna. -
AccountManager
memulai layanan ini untuk memulai proses autentikasi. MetodeonCreate()
layanan membuat instance objek pengautentikasi. Saat sistem ingin mengautentikasi akun pengguna untuk adaptor sinkronisasi aplikasi, sistem akan memanggil metodeonBind()
layanan untuk mendapatkanIBinder
untuk authenticator. Hal ini memungkinkan sistem melakukan panggilan lintas proses ke metode pengautentikasi. -
Opsional: Subkelas konkret dari
AbstractAccountAuthenticator
yang menangani permintaan autentikasi. -
Class ini menyediakan metode yang dipanggil
AccountManager
untuk mengautentikasi kredensial pengguna dengan server. Detail proses autentikasi sangat bervariasi, berdasarkan teknologi server yang digunakan. Anda harus membaca dokumentasi untuk software server Anda guna mempelajari lebih lanjut autentikasi. - File XML yang mendefinisikan adaptor sinkronisasi dan autentikator bagi sistem.
-
Komponen layanan autentikator dan adaptor sinkronisasi yang dijelaskan sebelumnya
ditentukan dalam
<service>
elemen dalam manifes aplikasi. Elemen ini berisi<meta-data>
elemen turunan yang memberikan data spesifik ke sistem:-
Elemen
<meta-data>
untuk layanan adaptor sinkronisasi menunjuk ke file XMLres/xml/syncadapter.xml
. Selanjutnya, file ini menentukan URI untuk layanan web yang akan disinkronkan dengan Penyedia Kontak, dan jenis akun untuk layanan web. -
Opsional: Elemen
<meta-data>
untuk authenticator menunjuk ke file XMLres/xml/authenticator.xml
. Selanjutnya, file ini menentukan jenis akun yang didukung authenticator ini, serta resource UI yang muncul selama proses autentikasi. Jenis akun yang ditentukan dalam elemen ini harus sama dengan jenis akun yang ditentukan untuk adaptor sinkronisasi.
-
Elemen
Data aliran sosial
Tabel android.provider.ContactsContract.StreamItems dan android.provider.ContactsContract.StreamItemPhotos mengelola data masuk dari jejaring sosial. Anda dapat menulis adaptor sinkronisasi yang menambahkan data streaming dari jaringan Anda sendiri ke tabel ini, atau Anda dapat membaca data streaming dari tabel ini dan menampilkannya di aplikasi Anda sendiri, atau keduanya. Dengan fitur ini, layanan dan aplikasi jejaring sosial Anda dapat diintegrasikan ke dalam pengalaman jejaring sosial Android.
Teks aliran sosial
Item aliran selalu dikaitkan dengan kontak mentah.
android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID ditautkan ke
nilai _ID
untuk kontak mentah. Jenis akun dan nama akun kontak mentah juga disimpan di baris item streaming.
Simpanlah data dari aliran Anda dalam kolom-kolom berikut:
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
- Wajib. Jenis akun pengguna untuk kontak mentah yang terkait dengan item streaming ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
- Wajib. Nama akun pengguna untuk kontak mentah yang terkait dengan item streaming ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
- Kolom identifier
-
Wajib. Anda harus menyisipkan kolom ID berikut saat Anda
menyisipkan item stream:
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: Nilai android.provider.BaseColumns#_ID dari kontak yang terkait dengan item forum ini.
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: Nilai android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY dari kontak yang terkait dengan item streaming ini.
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: Nilai android.provider.BaseColumns#_ID dari kontak mentah yang terkait dengan item forum ini.
- android.provider.ContactsContract.StreamItemsColumns#COMMENTS
- Opsional. Menyimpan informasi rangkuman yang bisa Anda tampilkan di awal item aliran.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
Teks item streaming, baik konten yang diposting oleh sumber item,
atau deskripsi beberapa tindakan yang menghasilkan item streaming. Kolom ini dapat berisi
format dan gambar resource sematan apa pun yang dapat dirender oleh
fromHtml()
. Penyedia dapat memangkas atau membuat elipsis pada konten yang panjang, tetapi akan mencoba menghindari pemisahan tag. - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- String teks yang berisi waktu saat item streaming disisipkan atau diperbarui, dalam bentuk milidetik sejak epoch. Aplikasi yang menyisipkan atau memperbarui item streaming bertanggung jawab untuk mengelola kolom ini; kolom ini tidak dikelola secara otomatis oleh Penyedia Kontak.
Untuk menampilkan informasi identifikasi item streaming, gunakan android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL, dan android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE untuk menautkan ke resource di aplikasi Anda.
Tabel android.provider.ContactsContract.StreamItems juga berisi kolom android.provider.ContactsContract.StreamItemsColumns#SYNC1 hingga android.provider.ContactsContract.StreamItemsColumns#SYNC4 untuk penggunaan eksklusif adapter sinkronisasi.
Foto aliran sosial
Tabel android.provider.ContactsContract.StreamItemPhotos menyimpan foto yang terkait
dengan item forum. Kolom
android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID tabel
ditautkan ke nilai di kolom _ID
dari
tabel android.provider.ContactsContract.StreamItems. Referensi foto disimpan dalam
tabel di kolom berikut:
- Kolom android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB).
- Representasi biner foto, yang diubah ukurannya oleh penyedia untuk penyimpanan dan tampilan. Kolom ini tersedia untuk kompatibilitas mundur dengan versi sebelumnya dari Penyedia Kontak yang menggunakannya untuk menyimpan foto. Namun, pada versi saat ini, Anda tidak boleh menggunakan kolom ini untuk menyimpan foto. Sebagai gantinya, gunakan android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID atau android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (keduanya dijelaskan dalam poin berikut) untuk menyimpan foto dalam file. Kolom ini sekarang berisi thumbnail foto, yang tersedia untuk dibaca.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
ID numerik foto untuk kontak mentah. Tambahkan nilai ini ke konstanta
DisplayPhoto.CONTENT_URI
untuk mendapatkan URI konten yang mengarah ke satu file foto, lalu panggilopenAssetFileDescriptor()
untuk mendapatkan handle ke file foto. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
URI konten yang mengarah langsung ke file foto untuk foto yang direpresentasikan oleh baris ini.
Panggil
openAssetFileDescriptor()
dengan URI ini untuk mendapatkan handle ke file foto.
Menggunakan tabel aliran sosial
Tabel-tabel ini sama fungsinya dengan tabel-tabel utama lainnya dalam Penyedia Kontak, kecuali:
- Tabel-tabel ini memerlukan izin akses tambahan. Untuk membacanya, aplikasi Anda harus memiliki izin android.Manifest.permission#READ_SOCIAL_STREAM. Untuk mengubahnya, aplikasi Anda harus memiliki izin android.Manifest.permission#WRITE_SOCIAL_STREAM.
-
Untuk tabel android.provider.ContactsContract.StreamItems, jumlah baris
yang disimpan untuk setiap kontak mentah dibatasi. Setelah batas ini tercapai,
Penyedia Kontak akan menyediakan ruang untuk baris item streaming baru dengan menghapus
baris yang memiliki
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP paling lama secara otomatis. Untuk mendapatkan
batas, kirim kueri ke URI konten
android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. Anda dapat membiarkan
semua argumen selain URI konten ditetapkan ke
null
. Kueri menampilkan Kursor yang berisi satu baris, dengan satu kolom android.provider.ContactsContract.StreamItems#MAX_ITEMS.
Class android.provider.ContactsContract.StreamItems.StreamItemPhotos menentukan sub-tabel android.provider.ContactsContract.StreamItemPhotos yang berisi baris foto untuk satu item streaming.
Interaksi aliran sosial
Data aliran media sosial yang dikelola oleh Penyedia Kontak, bersama dengan aplikasi kontak perangkat, menawarkan cara yang efektif untuk menghubungkan sistem jejaring sosial Anda dengan kontak yang ada. Tersedia fitur-fitur berikut:
- Dengan menyinkronkan layanan jejaring sosial Anda ke Penyedia Kontak dengan adaptor sinkronisasi, Anda dapat mengambil aktivitas terbaru untuk kontak pengguna dan menyimpannya di tabel android.provider.ContactsContract.StreamItems dan android.provider.ContactsContract.StreamItemPhotos untuk digunakan nanti.
- Selain sinkronisasi reguler, Anda dapat memicu adaptor sinkronisasi untuk mengambil data tambahan saat pengguna memilih kontak untuk dilihat. Hal ini memungkinkan adaptor sinkronisasi Anda mengambil foto beresolusi tinggi dan item streaming terbaru untuk kontak.
- Dengan mendaftarkan notifikasi ke aplikasi kontak perangkat dan Penyedia Kontak, Anda dapat menerima intent saat kontak dilihat, dan pada saat itu memperbarui status kontak dari layanan Anda. Pendekatan ini mungkin lebih cepat dan menggunakan lebih sedikit bandwidth daripada melakukan sinkronisasi penuh dengan adaptor sinkronisasi.
- Pengguna dapat menambahkan kontak ke layanan jejaring sosial Anda saat melihat kontak di aplikasi kontak perangkat. Anda mengaktifkannya dengan fitur "undang kontak", yang Anda aktifkan dengan kombinasi aktivitas yang menambahkan kontak yang ada ke jaringan Anda, dan file XML yang menyediakan aplikasi kontak perangkat dan Contacts Provider dengan detail aplikasi Anda.
Sinkronisasi item streaming reguler dengan Penyedia Kontak sama dengan sinkronisasi lainnya. Untuk mempelajari lebih lanjut sinkronisasi, lihat bagian Adaptor sinkronisasi Contacts Provider. Mendaftarkan notifikasi dan mengundang kontak akan dibahas di dua bagian berikutnya.
Pendaftaran untuk menangani tampilan jaringan sosial
Untuk mendaftarkan adaptor sinkronisasi Anda agar menerima notifikasi saat pengguna melihat kontak yang dikelola oleh adaptor sinkronisasi Anda:
-
Buat file bernama
contacts.xml
di direktorires/xml/
project Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. -
Dalam file ini, tambahkan elemen
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. Jika elemen ini sudah ada, langkah ini boleh dilewati. -
Untuk mendaftarkan layanan yang diberi tahu saat pengguna membuka halaman detail kontak di aplikasi kontak perangkat, tambahkan atribut
viewContactNotifyService="serviceclass"
ke elemen, denganserviceclass
adalah nama class yang sepenuhnya memenuhi syarat dari layanan yang harus menerima intent dari aplikasi kontak perangkat. Untuk layanan notifikasi, gunakan class yang memperluasIntentService
, agar layanan dapat menerima intent. Data dalam intent masuk berisi URI konten kontak mentah yang diklik pengguna. Dari layanan notifikasi, Anda dapat mengikat lalu memanggil adaptor sinkronisasi untuk memperbarui data kontak mentah.
Untuk mendaftarkan aktivitas agar dipanggil saat pengguna mengeklik item aliran atau foto atau keduanya:
-
Buat file bernama
contacts.xml
di direktorires/xml/
project Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. -
Dalam file ini, tambahkan elemen
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. Jika elemen ini sudah ada, langkah ini boleh dilewati. -
Untuk mendaftarkan salah satu aktivitas Anda agar menangani pengguna yang mengklik item streaming di aplikasi kontak perangkat, tambahkan atribut
viewStreamItemActivity="activityclass"
ke elemen, denganactivityclass
adalah nama class yang sepenuhnya memenuhi syarat dari aktivitas yang harus menerima intent dari aplikasi kontak perangkat. -
Untuk mendaftarkan salah satu aktivitas Anda agar menangani pengguna yang mengklik foto streaming di aplikasi kontak perangkat, tambahkan atribut
viewStreamItemPhotoActivity="activityclass"
ke elemen, denganactivityclass
adalah nama class yang sepenuhnya memenuhi syarat dari aktivitas yang harus menerima intent dari aplikasi kontak perangkat.
Elemen <ContactsAccountType>
dijelaskan lebih mendetail di
bagian Elemen<ContactsAccountType>.
Intent yang masuk berisi URI materi dari materi atau foto yang diklik pengguna. Untuk mendapatkan aktivitas terpisah bagi item teks dan foto, gunakan kedua atribut dalam file yang sama.
Berinteraksi dengan layanan jaringan sosial Anda
Pengguna tidak perlu keluar dari aplikasi kontak perangkat untuk mengundang kontak ke situs jejaring sosial Anda. Sebagai gantinya, Anda dapat meminta aplikasi kontak perangkat mengirimkan intent untuk mengundang kontak ke salah satu aktivitas Anda. Untuk menyiapkannya:
-
Buat file bernama
contacts.xml
di direktorires/xml/
project Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. -
Dalam file ini, tambahkan elemen
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. Jika elemen ini sudah ada, langkah ini boleh dilewati. -
Tambahkan atribut berikut:
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
adalah nama class yang sepenuhnya memenuhi syarat dari aktivitas yang harus menerima intent. Nilaiinvite_action_label
adalah string teks yang ditampilkan di menu Tambahkan Koneksi di aplikasi kontak perangkat.
Catatan: ContactsSource
adalah nama tag yang tidak digunakan lagi untuk
ContactsAccountType
.
Referensi contacts.xml
File contacts.xml
berisi elemen XML yang mengontrol interaksi adaptor sinkronisasi dan aplikasi Anda dengan aplikasi kontak dan Penyedia Kontak. Elemen
ini dijelaskan di bagian berikut.
Elemen <ContactsAccountType>
Elemen <ContactsAccountType>
mengontrol interaksi aplikasi Anda dengan aplikasi kontak. Sintaksnya adalah sebagai berikut:
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android" inviteContactActivity="activity_name" inviteContactActionLabel="invite_command_text" viewContactNotifyService="view_notify_service" viewGroupActivity="group_view_activity" viewGroupActionLabel="group_action_text" viewStreamItemActivity="viewstream_activity_name" viewStreamItemPhotoActivity="viewphotostream_activity_name">
terdapat di:
res/xml/contacts.xml
dapat berisi:
<ContactsDataKind>
Deskripsi:
Mendeklarasikan komponen Android dan label UI yang memungkinkan pengguna mengundang salah satu kontak mereka ke jejaring sosial, memberi tahu pengguna saat salah satu feed jejaring sosial mereka diperbarui, dan sebagainya.
Perhatikan bahwa awalan atribut android:
tidak diperlukan untuk atribut
dari <ContactsAccountType>
.
Atribut:
inviteContactActivity
- Nama class yang sepenuhnya memenuhi syarat dari aktivitas di aplikasi yang ingin Anda aktifkan saat pengguna memilih Tambahkan koneksi dari aplikasi kontak perangkat.
inviteContactActionLabel
-
String teks yang ditampilkan untuk aktivitas yang ditentukan dalam
inviteContactActivity
, di menu Tambahkan koneksi. Misalnya, Anda dapat menggunakan string "Ikuti di jaringan saya". Anda dapat menggunakan ID resource string untuk label ini. viewContactNotifyService
- Nama class yang sepenuhnya memenuhi syarat dari layanan di aplikasi Anda yang harus menerima notifikasi saat pengguna melihat kontak. Notifikasi ini dikirim oleh aplikasi kontak perangkat; notifikasi ini memungkinkan aplikasi Anda menunda operasi yang menggunakan banyak data hingga diperlukan. Misalnya, aplikasi Anda dapat merespons notifikasi ini dengan membaca dan menampilkan foto kontak beresolusi tinggi dan item streaming sosial terbaru. Fitur ini dijelaskan lebih detail di bagian Interaksi streaming media sosial.
viewGroupActivity
- Nama class yang sepenuhnya memenuhi syarat dari aktivitas di aplikasi Anda yang dapat menampilkan informasi grup. Saat pengguna mengklik label grup di aplikasi kontak perangkat, UI untuk aktivitas ini akan ditampilkan.
viewGroupActionLabel
-
Label yang ditampilkan aplikasi kontak untuk kontrol UI yang memungkinkan
pengguna melihat grup di aplikasi Anda.
Identifier resource string diperbolehkan untuk atribut ini.
viewStreamItemActivity
- Nama class yang sepenuhnya memenuhi syarat dari aktivitas di aplikasi Anda yang diluncurkan oleh aplikasi kontak perangkat saat pengguna mengklik item feed untuk kontak mentah.
viewStreamItemPhotoActivity
- Nama class yang sepenuhnya memenuhi syarat dari aktivitas di aplikasi Anda yang diluncurkan oleh aplikasi kontak perangkat saat pengguna mengklik foto di item feed untuk kontak mentah.
Elemen <ContactsDataKind>
Elemen <ContactsDataKind>
mengontrol tampilan baris data kustom aplikasi Anda di UI aplikasi kontak. Sintaksnya adalah sebagai berikut:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
terdapat di:
<ContactsAccountType>
Deskripsi:
Gunakan elemen ini agar aplikasi kontak menampilkan konten baris data kustom sebagai
bagian dari detail kontak mentah. Setiap elemen turunan <ContactsDataKind>
dari <ContactsAccountType>
merepresentasikan jenis baris data kustom yang ditambahkan adaptor
sinkronisasi ke tabel ContactsContract.Data
. Tambahkan satu elemen
<ContactsDataKind>
untuk setiap jenis MIME kustom yang Anda gunakan. Anda tidak
perlu menambahkan elemen jika memiliki baris data kustom yang datanya tidak ingin Anda tampilkan.
Atribut:
android:mimeType
-
Jenis MIME kustom yang telah Anda tentukan untuk salah satu jenis baris data kustom di tabel
ContactsContract.Data
. Misalnya, nilaivnd.android.cursor.item/vnd.example.locationstatus
dapat berupa jenis MIME kustom untuk baris data yang mencatat lokasi terakhir yang diketahui dari kontak. android:icon
- Resource drawable Android yang ditampilkan aplikasi kontak di samping data Anda. Gunakan ini untuk menunjukkan kepada pengguna bahwa data berasal dari layanan Anda.
android:summaryColumn
- Nama kolom untuk nilai pertama dari dua nilai yang diambil dari baris data. Nilai ditampilkan sebagai baris pertama entri untuk baris data ini. Baris pertama dimaksudkan untuk digunakan sebagai ringkasan data, tetapi bersifat opsional. Lihat juga android:detailColumn.
android:detailColumn
-
Nama kolom untuk nilai kedua dari dua nilai yang diambil dari baris data. Nilai ditampilkan sebagai baris kedua entri untuk baris data ini. Lihat juga
android:summaryColumn
.
Fitur tambahan Penyedia Kontak
Selain fitur utama yang dijelaskan di bagian sebelumnya, Penyedia Kontak menawarkan fitur berguna berikut untuk menangani data kontak:
- Grup kontak
- Fitur foto
Grup kontak
Penyedia Kontak dapat secara opsional memberi label pada kumpulan kontak terkait dengan data grup. Jika server yang terkait dengan akun pengguna ingin mempertahankan grup, adaptor sinkronisasi untuk jenis akun tersebut harus mentransfer data grup antara Penyedia Kontak dan server. Saat pengguna menambahkan kontak baru ke server, lalu memasukkan kontak ini ke dalam grup baru, adaptor sinkronisasi harus menambahkan grup baru ke tabel ContactsContract.Groups
. Grup atau grup tempat kontak mentah
berada disimpan dalam tabel ContactsContract.Data
, menggunakan
jenis MIME ContactsContract.CommonDataKinds.GroupMembership
.
Jika Anda mendesain adaptor sinkronisasi yang akan menambahkan data kontak mentah dari server ke Penyedia Kontak, dan Anda tidak menggunakan grup, Anda harus memberi tahu Penyedia untuk membuat data Anda terlihat. Dalam kode yang dieksekusi saat pengguna menambahkan akun
ke perangkat, perbarui baris ContactsContract.Settings
yang ditambahkan Penyedia Kontak untuk akun tersebut. Di baris ini, tetapkan nilai kolom
Settings.UNGROUPED_VISIBLE
ke 1. Jika Anda melakukannya, Penyedia Kontak akan selalu
membuat data kontak Anda terlihat, meskipun Anda tidak menggunakan grup.
Foto kontak
Tabel ContactsContract.Data
menyimpan foto sebagai baris dengan jenis MIME
Photo.CONTENT_ITEM_TYPE
. Kolom
CONTACT_ID
baris ditautkan ke
kolom _ID
kontak mentah yang menjadi miliknya.
Class ContactsContract.Contacts.Photo
menentukan sub-tabel
ContactsContract.Contacts
yang berisi informasi foto untuk foto utama kontak, yang merupakan foto utama dari kontak mentah utama kontak. Demikian pula,
class ContactsContract.RawContacts.DisplayPhoto
menentukan sub-tabel
dari ContactsContract.RawContacts
yang berisi informasi foto untuk
foto utama kontak mentah.
Dokumentasi referensi untuk ContactsContract.Contacts.Photo
dan
ContactsContract.RawContacts.DisplayPhoto
berisi contoh
pengambilan informasi foto. Tidak ada class praktis untuk mengambil thumbnail utama
untuk kontak mentah, tetapi Anda dapat mengirim kueri ke tabel
ContactsContract.Data
, memilih _ID
kontak mentah, Photo.CONTENT_ITEM_TYPE
, dan kolom IS_PRIMARY
untuk menemukan baris foto utama kontak mentah.
Data aliran sosial untuk seseorang bisa juga disertai foto. Foto ini disimpan dalam tabel android.provider.ContactsContract.StreamItemPhotos, yang dijelaskan secara lebih mendetail di bagian Foto feed media sosial.