Load contacts much faster

This commit is contained in:
Benoit Marty 2020-07-09 15:49:10 +02:00
parent 4c1d50d554
commit 3142442e5c

View File

@ -31,7 +31,7 @@ class ContactsDataSource @Inject constructor(
@WorkerThread @WorkerThread
fun getContacts(): List<MappedContact> { fun getContacts(): List<MappedContact> {
val result = mutableListOf<MappedContact>() val map = mutableMapOf<Long, MappedContactBuilder>()
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
measureTimeMillis { measureTimeMillis {
@ -53,28 +53,38 @@ class ContactsDataSource @Inject constructor(
val id = cursor.getLong(ContactsContract.Contacts._ID) ?: continue val id = cursor.getLong(ContactsContract.Contacts._ID) ?: continue
val displayName = cursor.getString(ContactsContract.Contacts.DISPLAY_NAME) ?: continue val displayName = cursor.getString(ContactsContract.Contacts.DISPLAY_NAME) ?: continue
val currentContact = MappedContactBuilder( val mappedContactBuilder = MappedContactBuilder(
id = id, id = id,
displayName = displayName displayName = displayName
) )
cursor.getString(ContactsContract.Data.PHOTO_URI) cursor.getString(ContactsContract.Data.PHOTO_URI)
?.let { Uri.parse(it) } ?.let { Uri.parse(it) }
?.let { currentContact.photoURI = it } ?.let { mappedContactBuilder.photoURI = it }
map[id] = mappedContactBuilder
}
}
}
// Get the phone numbers // Get the phone numbers
contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
arrayOf( arrayOf(
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.NUMBER ContactsContract.CommonDataKinds.Phone.NUMBER
), ),
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", null,
arrayOf(id.toString()), null,
null) null)
?.use { innerCursor -> ?.use { innerCursor ->
while (innerCursor.moveToNext()) { while (innerCursor.moveToNext()) {
val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
?.let { map[it] }
?: continue
innerCursor.getString(ContactsContract.CommonDataKinds.Phone.NUMBER) innerCursor.getString(ContactsContract.CommonDataKinds.Phone.NUMBER)
?.let { ?.let {
currentContact.msisdns.add( mappedContactBuilder.msisdns.add(
MappedMsisdn( MappedMsisdn(
phoneNumber = it, phoneNumber = it,
matrixId = null matrixId = null
@ -88,18 +98,22 @@ class ContactsDataSource @Inject constructor(
contentResolver.query( contentResolver.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI, ContactsContract.CommonDataKinds.Email.CONTENT_URI,
arrayOf( arrayOf(
ContactsContract.CommonDataKinds.Email.CONTACT_ID,
ContactsContract.CommonDataKinds.Email.DATA ContactsContract.CommonDataKinds.Email.DATA
), ),
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", null,
arrayOf(id.toString()), null,
null) null)
?.use { innerCursor -> ?.use { innerCursor ->
while (innerCursor.moveToNext()) { while (innerCursor.moveToNext()) {
// This would allow you get several email addresses // This would allow you get several email addresses
// if the email addresses were stored in an array // if the email addresses were stored in an array
val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Email.CONTACT_ID)
?.let { map[it] }
?: continue
innerCursor.getString(ContactsContract.CommonDataKinds.Email.DATA) innerCursor.getString(ContactsContract.CommonDataKinds.Email.DATA)
?.let { ?.let {
currentContact.emails.add( mappedContactBuilder.emails.add(
MappedEmail( MappedEmail(
email = it, email = it,
matrixId = null matrixId = null
@ -109,14 +123,12 @@ class ContactsDataSource @Inject constructor(
} }
} }
result.add(currentContact.build()) }.also { Timber.d("Took ${it}ms to fetch ${map.size} contact(s)") }
}
}
}
}.also { Timber.d("Took ${it}ms to fetch ${result.size} contact(s)") }
return result return map
.values
.filter { it.emails.isNotEmpty() || it.msisdns.isNotEmpty() } .filter { it.emails.isNotEmpty() || it.msisdns.isNotEmpty() }
.map { it.build() }
} }
private fun Cursor.getString(column: String): String? { private fun Cursor.getString(column: String): String? {