Skip to content

Instantly share code, notes, and snippets.

@srayhunter
Last active April 26, 2024 20:22
Show Gist options
  • Save srayhunter/47ab2816b01f0b00b79150150feb2eb2 to your computer and use it in GitHub Desktop.
Save srayhunter/47ab2816b01f0b00b79150150feb2eb2 to your computer and use it in GitHub Desktop.
Android - Get phone number and email address from Contacts
private class FetchContacts extends AsyncTask<Void, Void, ArrayList<Contact>> {
private final String DISPLAY_NAME = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME;
private final String FILTER = DISPLAY_NAME + " NOT LIKE '%@%'";
private final String ORDER = String.format("%1$s COLLATE NOCASE", DISPLAY_NAME);
@SuppressLint("InlinedApi")
private final String[] PROJECTION = {
ContactsContract.Contacts._ID,
DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER
};
@Override
protected ArrayList<Contact> doInBackground(Void... params) {
try {
ArrayList<Contact> contacts = new ArrayList<>();
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, PROJECTION, FILTER, null, ORDER);
if (cursor != null && cursor.moveToFirst()) {
do {
// get the contact's information
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String name = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME));
Integer hasPhone = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
// get the user's email address
String email = null;
Cursor ce = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null);
if (ce != null && ce.moveToFirst()) {
email = ce.getString(ce.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
ce.close();
}
// get the user's phone number
String phone = null;
if (hasPhone > 0) {
Cursor cp = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null);
if (cp != null && cp.moveToFirst()) {
phone = cp.getString(cp.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
cp.close();
}
}
// if the user user has an email or phone then add it to contacts
if ((!TextUtils.isEmpty(email) && android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
&& !email.equalsIgnoreCase(name)) || (!TextUtils.isEmpty(phone))) {
Contact contact = new Contact();
contact.name = name;
contact.email = email;
contact.phoneNumber = phone;
contacts.add(contact);
}
} while (cursor.moveToNext());
// clean up cursor
cursor.close();
}
return contacts;
} catch (Exception ex) {
return null;
}
}
@Override
protected void onPostExecute(ArrayList<Contact> contacts) {
if (contacts != null) {
// success
mContacts = contacts;
} else {
// show failure
// syncFailed();
}
}
}
@srayhunter
Copy link
Author

This was written a long time ago. You could leverage rxjava or coroutines to run the process on a background computation or io thread. You could also run the 2nd queries (email, phone number) under different threads and merge them together to create the contact. This might optimize the overall process. Do you want all the contacts? You could limit the response back and page the results back to the user.

@lokhandesh
Copy link

Thanks @srayhunter for reply.
I agree with your point like access contact on different thread. Currently I am following same thing.
Yes I want all the contacts. In my mobile having 700-800 contact,that's why it is taking 7 seconds.
Is there Any other approach where using single query we can get phone number and email of all contact?

@srayhunter
Copy link
Author

srayhunter commented Jun 14, 2021

@lokhandesh the queries are different URIs so that is why there are the different queries. So, I would try and do the first query and then do the 2 other queries each on separate threads and then merge them together. With rxjava you can look at merging and with kotlin coroutines you can look at flow combine. Then you can move this async task to a coroutine or rxjava observable.

This loops through each contact and then does the 2 queries. You could get all the contacts and then do the queries async and update your list as they are retrieved for each contact id.

@lokhandesh
Copy link

@srayhunter looks like with above approach it will save around half time, that means 3.5 seconds in my scenario.
Okay will try with approach mentioned by you.

@nishi13tiwari
Copy link

Can we fetch deleted contacts?

@srayhunter
Copy link
Author

@nishi13tiwari I dont think deleted contacts will be fetched. I think once they are deleted, they are removed from the device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment