2

in my app i am listing contacts in a listview. no of contacts is 1000+. i get the contacts

by using ContentResolver query that is cr.query(...),store the values in an arraylist

and after that load the array list in setListAdapter(...). to display the all contacts my

apps takes nearly 1 minute so that i use Async task but there is no big differences by using the async task.

i need to display all contacts within 2 to 4 seconds. i check in the default contacts application on android simulator which is load within in 2 to 4 seconds. i have spend

long time in google. but i could not get any helpful solution. please help me how to fast the loading contacts on listview. please help me.

my coding sample:

    private ArrayList<ContactListEntry> loadContactListInternal(String searchString) {
        ArrayList<ContactListEntry> contactList = new ArrayList<ContactListEntry>();
    ContentResolver cr = getContentResolver();
    Cursor cur = null;
    String[] projection = new String[] {BaseColumns._ID,ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts.PHOTO_ID};
    ....
        cur=cr.query(ContactsContract.Contacts.CONTENT_URI, projection, selection, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");

    while (cur.moveToNext()) {
         int id = Integer.parseInt(cur.getString(0));
             ....   
        if (input !=null)
            photo = BitmapFactory.decodeStream(input);
         ....
        ArrayList<ContactListEntry.PhoneEntry> phoneEntries = new ArrayList<ContactListEntry.PhoneEntry>();

            String[] projection1 = new String[] {ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.TYPE};    
            Cursor pcur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,projection1, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { String.valueOf(id) }, null);
            while (pcur.moveToNext()) {
                ...
            }
            pcur.close();

            ContactListEntry entry = new ContactListEntry(id, name, photo, phoneEntries);
            contactList.add(entry);
    }
    cur.close();

    return contactList;
}
    .....
    in another class
        private void selectionUpdated() {
                ....
         setListAdapter(new SelectedArrayAdapter(this, app.selectedContacts));
            ... 
       }
M.A.Murali
  • 9,988
  • 36
  • 105
  • 182
  • What exactly do you **show** in the list view? – Boris Strandjev Apr 25 '12 at 10:14
  • i show contacts name and phone number with check box on the right side and for next process i store other values. – M.A.Murali Apr 25 '12 at 10:21
  • Here is one more thread where we tried improving the performance: http://stackoverflow.com/questions/9546047/fetching-a-large-number-of-contacts/9546248#9546248. As you can see again I was the only one daring to answer. The OP didn't find any cleaner solution – Boris Strandjev Apr 25 '12 at 11:09

5 Answers5

2

Use the Concept of projections and selection arguments to retrive the contacts in my case for 500 contacts intially it was taking 12 sec.

Now it is taking 350ms(lessthan second)

void getAllContacts() {
    long startnow;
    long endnow;

    startnow = android.os.SystemClock.uptimeMillis();
    ArrayList arrContacts = new ArrayList();

    Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
    Cursor cursor = ctx.getContentResolver().query(uri, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER,   ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.Contacts._ID}, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");

    cursor.moveToFirst();
    while (cursor.isAfterLast() == false) {

        String contactNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
        String contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        int phoneContactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
        int contactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
        Log.d("con ", "name " + contactName + " " + " PhoeContactID " + phoneContactID + "  ContactID " + contactID)

        cursor.moveToNext();
    }
    cursor.close();
    cursor = null;

    endnow = android.os.SystemClock.uptimeMillis();
    Log.d("END", "TimeForContacts " + (endnow - startnow) + " ms");
}

More information on this link http://www.blazin.in/2016/02/loading-contacts-fast-from-android.html ....

Bhushan Shirsath
  • 258
  • 3
  • 12
1

So your problem is that you do a lot of subqueries for each contact. I has the same issue once upon a time. My case was that I showed many contacts and allowed the user to click on any of them. After that I started processing the contact in another activity.

Back then I finally decided that I should display only the name and lazily fetch all the other data later on, just before I launch the next activity. This was amazing: decreased the speed of my program almost by a factor of 200, and the operations became completely invisible to the user.

The default android list does the same if I am not wrong - it displays only the name, and later on loads all the other contact-related data.

Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
  • yes i use two queries for get detail that is in the first query i get id,name... and in the second query i pass contact id as parameter to get the phone number and type. but two query is need(that is subquery) to get phone no and such detail. is any way combine into one or in a single query to get all detail? please my queries in question. – M.A.Murali Apr 25 '12 at 10:48
  • 1
    @murali_ma you don't use two queries. You use `n + 1` queries where n is the number of contacts in the phone. I will search a bit more about that, but back then I tried doing the same as your idea and it was futile. – Boris Strandjev Apr 25 '12 at 11:04
1

i use cursor adapter and i cut the databse,arrayadapter and optimize the code.

M.A.Murali
  • 9,988
  • 36
  • 105
  • 182
0

Consider having just one query and getting rid of the sub query idea (as already suggested). You can achieve speed by just querying using the Content Uri:

"ContactsContract.CommonDataKinds.Phone.CONTENT_URI"

This URI also has the "ContactsContract.Contacts.DISPLAY_NAME" field.

You might also want to consider doing this query and working with your adapter in a seperate thread to make it completely transparent.

This worked for me.

Jimmy Ilenloa
  • 1,989
  • 21
  • 21
0

OPTIMIZED SOLUTION HERE.....

private static final String[] PROJECTION = new String[] {
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.Phone.NUMBER
    };
.
.
.

ContentResolver cr = getContentResolver();
        Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
        if (cursor != null) {
            try {
                final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
                final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

                String name, number;
                while (cursor.moveToNext()) {
                    name = cursor.getString(nameIndex);
                    number = cursor.getString(numberIndex);
                }
            } finally {
                cursor.close();
            }
        }

CHEERS...:)

Melbourne Lopes
  • 4,817
  • 2
  • 34
  • 36