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?
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
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.
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));
}
}