Search code examples
androidperformancekotlinaddressbook

How to speed up this email address collection (Android/Kotlin)?


I compiled this function to retrieve all email addresses from Android address book from several google results. It works, but it needs ~5 seconds to return 294 addresses. This seems very slow to me.

Especially the many steps and sub-queries seem a bit unnecessary to me. Maybe I can get the resulting array in a single query instead of using the ID and the many sub-queries? Unfortunately, I found no way yet.

TLDR: Is there a way I can retrieve the email addresses faster than with this code?

fun getAllEmails(contentResolver: ContentResolver): String {
    val emailList = mutableListOf<String>()

    // Query the Contacts table
    try {
        val cursor = contentResolver.query(
            ContactsContract.Contacts.CONTENT_URI,
            null,
            null,
            null,
            null
        )
        cursor?.use {
            while (it.moveToNext()) {
                val id = it.getString(it.getColumnIndex(ContactsContract.Contacts._ID))

                // Query the Email table
                val emailCursor = contentResolver.query(
                    ContactsContract.CommonDataKinds.Email.CONTENT_URI,
                    null,
                    "${ContactsContract.CommonDataKinds.Email.CONTACT_ID} = ?",
                    arrayOf(id),
                    null
                )

                emailCursor?.use { emailCursor ->
                    while (emailCursor.moveToNext()) {
                        val email = emailCursor.getString(emailCursor.getColumnIndex(
                            ContactsContract.CommonDataKinds.Email.ADDRESS))
                        emailList.add(email)
                    }
                }
            }
        }
        return emailList.joinToString(",")

    } catch (e: Exception) {
        e.printStackTrace()
        return "" // got no permissions?
    }
}

Solution

  • Query directly the emails table.

    val cursor = contentResolver.query(
            ContactsContract.CommonDataKinds.Email.CONTENT_URI,
            arrayOf(ContactsContract.CommonDataKinds.Email.ADDRESS),
            null, null, null)
    
    cursor?.use {
        while (it.moveToNext()) {
            val email = it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS))
            emailList.add(email)
        }
    }
    return emailList.joinToString(",")
    

    Add arrayOf(ContactsContract.CommonDataKinds.Email.ADDRESS) to your cursor to select the emails, and get the email directly with only 1 loop and query. Let me know if you benchmark it.