androidkotlinandroid-recyclerviewandroid-permissionsandroid-contacts

Black screen and slow startup on starting app, when getting contact information into a RecyclerView?


I have a problem with a slow start and black screen when getting contact information into RecyclerView. And, the problem is gone when deleting the process. Below is the function of getContacts, if anyone can help. Thank you...

private fun getContactList() {
        val uri: Uri = ContactsContract.Contacts.CONTENT_URI
        // Sort by ascending
        val sort: String = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" ASC"
        // Initialize Cursor
        val cursor: Cursor = requireActivity().contentResolver.query(uri, null, null, null, sort)!!
        // Check condition
        if (cursor.count > 0) {
            while (cursor.moveToNext()) {
                val id: String = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID))
                val name: String = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))
                val img: String = getPhotoUriFromID(id).toString()
                val phoneUri: Uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
                val selection: String = ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" =?"
                // Initialize phone cursor
                val phoneCursor: Cursor = requireActivity().contentResolver.query(phoneUri, null, selection,
                    arrayOf(id), null)!!
                // Check condition
                if (phoneCursor.moveToNext()) {
                    val number: String = phoneCursor.getString(phoneCursor
                        .getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER))
                    // Initialize Contact Model
                    val model = ContactModel(name, number, img)
                    contactArr.add(model)
                    groupListAdapter.notifyDataSetChanged()
                    // Close Phone Cursor
                    phoneCursor.close()
                }
            }
            // Close Cursor
            cursor.close()
        }
    }

Solution

  • You have two major issues in your code:

    1. You're probably running the above queries on the UI thread which blocks the entire phone until the query finishes loading, which is really bad user-experience.
    2. Your code runs one query to fetch all contacts, and then more queries per contact, that means if your user has 5000 contacts your code will need to do 5000 queries which can take a long time to complete.

    To fix issue #1, you should call your code asynchronously and update your RecyclerView when the query finishes to load your items on screen.

    There are many ways to do this, as simply as an AsyncTask, and more advanced like AsyncListUtil

    here are some resources:

    1. https://androidwave.com/implementation-of-recyclerview-with-cursor-adapter/
    2. https://medium.com/android-news/how-to-use-asynclistutil-16b5175bb468

    Issue #2 can be fixed by running your query directly on the ContactsContract.Data table instead of the ContactsContract.Contacts table.

    The Data table contains all information on all contacts, so you can get all your need in one big query which is much faster then multiple smaller queries.

    Here's an example on how to do that: https://stackoverflow.com/a/52602698/819355