Getting name and email from contact list is very slow
Asked Answered
B

3

15

I'm implementing an AutoCompleteTextView and I need Name and E-Mail of all my contacts. I found this snippet that I'm running asynchronously but it's very slow.

ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

if (cur.getCount() > 0) {               
    while (cur.moveToNext()) {                  
        String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));                   
        String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

        Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null); 

            while (emailCur.moveToNext()) { 

                String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
                    autoCompleteAdapter.add(name + " - " + email);
            }

            emailCur.close();
        }
    }
}

I'm performing a sort of inner query and I think that's the problem. Is there a way to tune it and make it faster?

Belongings answered 24/8, 2012 at 12:26 Comment(2)
Did you manage to get it working ?Insignia
The outer if (cur.getCount() > 0) is redundant and may be removed.Bryson
A
57
private static final String[] PROJECTION = new String[] {
    ContactsContract.CommonDataKinds.Email.CONTACT_ID,
    ContactsContract.Contacts.DISPLAY_NAME,
    ContactsContract.CommonDataKinds.Email.DATA
};

...

ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
    try {
        final int contactIdIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.CONTACT_ID);
        final int displayNameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
        final int emailIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
        long contactId;
        String displayName, address;
        while (cursor.moveToNext()) {
            contactId = cursor.getLong(contactIdIndex);
            displayName = cursor.getString(displayNameIndex);
            address = cursor.getString(emailIndex);
            ...
        }
    } finally {
        cursor.close();
    }
}

few notes:

  • use just ContactsContract.CommonDataKinds.Email.CONTENT_URI to get information you need, see ContactsContract.CommonDataKinds.Email for information what columns you can query
  • use projection to get only those columns you really need, you save some memory and increase query performance
  • get column indexes only once, just before the while cycle
Argument answered 25/8, 2012 at 11:42 Comment(1)
how can i read whole v-card in efficient way it means to read whole address book.Suspensoid
E
6

You should not query directly the ContactsContract.Contacts

Make just one query on the ContactsContract.CommonDataKinds with the email data kind.

The ContactsContract.CommonDataKinds.Email inherits a lot of other interfaces that you can use to build your projection. (see inherited constants from the documentation)

For example :

import android.provider.ContactsContract.CommonDataKinds.Email;

[...]

public static final String[]  EMAILS_PROJECTION = new String[] {
    Email._ID,
    Email.DISPLAY_NAME_PRIMARY,
    Email.ADDRESS
};

to be used with the

Email.CONTENT_URI

You can retrieve a lot of information (such as user id, user display name ...) directly from the email data kind.

EDIT:

I just realized you're trying to build an AutoCompleteTextView.

You should override the runQueryOnBackgroundThread method and the convertToString of your CursorAdapter and use the Email.CONTENT_FILTER_URI

I really strongly suggest you to take a look at the ApiDemo samples.

Especially the AutoComplete4.java sample that you can find HERE.

Ephialtes answered 24/8, 2012 at 13:2 Comment(1)
Thanks Timothée, your explanation is very well done. Too bad I can't mark both answers as correct. I think that biegleux's answer is very good (works incredibly well) for other users looking for a quick snippet.Belongings
W
0
ContentResolver cr = mContext.getContentResolver(); 
Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, PROJECTION, "HAS_PHONE_NUMBER <> 0", null, null); 

if (cursor!= null) 
{ 
    final int displayNameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); 
    final int numberIndex = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER); 
    final int idIndex= cursor.getColumnIndex(ContactsContract.Contacts._ID); 
    String displayName, number = null, idValue; 

    while (cursor.moveToNext()) 
    {
        displayName = cursor.getString(displayNameIndex);
        idValue= cursor.getString(idIndex);

        Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, "contact_id = '" + idValue + "'", null, null);
        phones.moveToFirst();

        try 
        {
            number = phones.getString(phones.getColumnIndex("data1"));
        }
        catch (CursorIndexOutOfBoundsException e)
        {
        }

        phones.close();
        userList.add(new ContactModel(displayName, number, null));
    }
}
Weisberg answered 31/7, 2016 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.