I have written the following query to read contacts from a device.
private fun getContactPhoneNumbers(resolver: ContentResolver): Map<String, NameAndPhoneList> {
val startTime = System.nanoTime()
val map = hashMapOf<String, NameAndPhoneList>()
val projection = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER,
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI
)
val selection =
"${ContactsContract.Contacts.DISPLAY_NAME} NOT LIKE '' and ${ContactsContract.Contacts.DISPLAY_NAME} NOT NULL"
resolver.query(
ContactsContract.Contacts.CONTENT_URI,
projection,
selection,
null,
null,
null
)?.let { cursor ->
if (cursor.count > 0) {
while (cursor.moveToNext()) {
val id: String? =
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
val name: String? =
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
val photoUri =
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))
val phone =
if (cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
val pCur: Cursor = resolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
arrayOf(id),
null
)!!
val numbers = mutableListOf<String>()
while (pCur.moveToNext()) {
val phoneNo: String = pCur.getString(
pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER
)
)
numbers.add(phoneNo)
}
pCur.close()
numbers
} else
null
// take contacts which either have email or phone numbers
if (id != null && name != null) {
map[id] = NameAndPhoneList(name, phone, photoUri?.let { Uri.parse(it) })
}
}
}
cursor.close()
}
val endTime = System.nanoTime() - startTime
Timber.i("$CONTACT_SYNC_PHONE_MAP_QUERY_TIME = $endTime")
return map
}
private data class NameAndPhoneList(
val name: String,
val phoneList: List<String>?,
val imageUri: Uri?
)
this is taking 112877872699 ns (~2 min) for a phonebook of length 6,300 contacts. Is this expected or can we optimize further?
for 6,300 contacts (assuming all have a phone) you're making 6,301 queries, which is why it's so slow...
Instead you can benefit from ContactsContract's "implicit join" feature, which allows you to get Contacts.CONTENT_URI
fields when querying over the Data.CONTENT_URI
table.
So, just query directly over the Data table, get all the phones including the CONTACT_ID
, DISPLAY_NAME
, etc. fields, and put it in some map contact-id => data.
Here's sample code in Java that can help - https://stackoverflow.com/a/44383937/819355