performance – Android Contacts provider get only phone contacts with all emails-ThrowExceptions

Exception or error:

I need to get all phone contacts and their email address and photo uri:

This is what am doing:

private void getContacts() {

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

        if (cur.getCount() > 0) {
            while (cur.moveToNext()) {

                // if
                // (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))
                // > 0) {

                Contact contact = new Contact();

                String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));

                Uri uri = getContactPhotoUri(Long.parseLong(id));
                // set photoUri
                contact.setContactPhotoUri(uri);

                // set name
                contact.setContactName(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));

                // get the phone number
                Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
                while (pCur.moveToNext()) {

                    // set phone munber
                    contact.setContactNumber(pCur.getString(pCur
                            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                    contacts.add(contact);

                }
                pCur.close();

                // get email and type
                Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[] { id }, null);
                while (emailCur.moveToNext()) {
                    // This would allow you get several email addresses
                    // if the email addresses were stored in an array

                    // set email
                    contact.setContactEmail(emailCur.getString(emailCur
                            .getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)));

                    contacts.add(contact);

                }
                emailCur.close();

            }
        }

        cur.close();
        contactAdapter = new ContactAdapter(this, R.id.contactList, contacts);

        // }

    }

    public Uri getContactPhotoUri(long contactId) {
        Uri photoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
        photoUri = Uri.withAppendedPath(photoUri, Contacts.Photo.CONTENT_DIRECTORY);
        return photoUri;
    }

My problem am getting all contacts including gmail contacts, i dont want gmail contacts to be included. And the time taken is also very slow. How do i optimize this, I know its taking time coz i am using many cursors.. but dont know how to make a single cusror that can give me name email number photo uri …Thanks!

UPDATED FINAL:

private void getContacts() {

    ContentResolver cr = getContentResolver();

    Cursor cur = cr.query(Data.CONTENT_URI, new String[] { Data.CONTACT_ID, Data.MIMETYPE, Email.ADDRESS,
            Contacts.DISPLAY_NAME, Phone.NUMBER }, null, null, Contacts.DISPLAY_NAME);

    Contact contact;

    if (cur.getCount() > 0) {

        while (cur.moveToNext()) {

            String id = cur.getString(cur.getColumnIndex(Data.CONTACT_ID));

            String mimeType = cur.getString(cur.getColumnIndex(Data.MIMETYPE));

            if (allContacts.containsKey(id)) {
                // update contact
                contact = allContacts.get(id);
            } else {
                contact = new Contact();
                allContacts.put(id, contact);
                // set photoUri
                contact.setContactPhotoUri(getContactPhotoUri(Long.parseLong(id)));
            }

            if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE))
                // set name
                contact.setContactName(cur.getString(cur.getColumnIndex(Contacts.DISPLAY_NAME)));

            if (mimeType.equals(Phone.CONTENT_ITEM_TYPE))
                // set phone munber
                contact.setContactNumber(cur.getString(cur.getColumnIndex(Phone.NUMBER)));

            if (mimeType.equals(Email.CONTENT_ITEM_TYPE))
                // set email
                contact.setContactEmail(cur.getString(cur.getColumnIndex(Email.ADDRESS)));

        }
    }

    cur.close();
    // get contacts from hashmap
    contacts.clear();
    contacts.addAll(allContacts.values());

    // remove null contacts
    for (Contact _contact : contacts) {

        if (_contact.getContactName() == null && _contact.getContactNumber() == null
                && _contact.getContactEmail() == null) {
            contacts.remove(_contact);
            break;
        }

    }

    contactAdapter = new ContactAdapter(this, R.id.contactList, contacts);
    contactAdapter.notifyDataSetChanged();

}

public Uri getContactPhotoUri(long contactId) {
    Uri photoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    photoUri = Uri.withAppendedPath(photoUri, Contacts.Photo.CONTENT_DIRECTORY);
    return photoUri;
}
How to solve:

You should be able to get all the information needed in one query on Data.CONTENT_URI,
Check out “android.provider.ContactsContract.Data” table and the examples on how to query different types of data Email,Phone,Photo etc…
http://developer.android.com/reference/android/provider/ContactsContract.Data.html

For example:

Cursor data = cntx.getContentResolver().query(Data.CONTENT_URI, new String[] {Data._ID,Data.MIMETYPE,Email.ADDRESS,Photo.PHOTO},Data.CONTACT_ID + "=?" + " AND " + "(" +  Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "' OR " + Data.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE +"')",
                        new String[] {String.valueOf(contactId)}, null);

Should bring you all the information you need regarding one specific contactId, you could theoretically ask for all contacts and sort the information yourself.

As for filtering gmail contacts this is a more complex issue, take a look at ACCOUNT_NAME / TYPE http://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html
parameter and a discussion regarding this issue here:
What is the default Account Type / Name for contacts on Android Contact Application?

Leave a Reply

Your email address will not be published. Required fields are marked *