I am trying to get contacts of the android device. I found a great sample code here
However, when trying to populate a ListActivity
with ArrayAdapter
that is using that code it is taking a lot of time - almost 4 seconds on galaxy s2 and much more on older devices.
I need to improve that performance. What I thought is to implements Cursor
that will hold more than one dimension Cursor
, and use SimpleCursorAdapter
as the list adapter.
I see few problems with this approach:
Is there a better/easier way to do that?
EDIT:
here is my code:
public List<ContactData> readContacts(){
ContentResolver cr = getContentResolver();
List<ContactData> cd = new ArrayList<ContactData>();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, ContactsContract.Contacts.DISPLAY_NAME);
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));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
// 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()) {
String phone = pCur.getString(
pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (!Utils.isEmpty(phone)) {
cd.add(new ContactData(id, name, phone));
}
}
pCur.close();
}
}
}
return cd;
}
EDIT 2:
managed to fix it by changing it to only one query:
public List<ContactData> readContacts(){
ContentResolver cr = getContentResolver();
List<ContactData> cd = new ArrayList<ContactData>();
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.Phone._ID,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY},
ContactsContract.CommonDataKinds.Phone.NUMBER + " IS NOT NULL",
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY);
while (pCur.moveToNext()) {
String phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String id = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
String name = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY));
ContactData cd1 = contactDataProvider.get();
cd1.id = id;
cd1.name = name;
cd1.phone = phone;
cd.add(cd1);
}
pCur.close();
return cd;
}
You can get name and ID at the same time you get the phone number:
String[] PROJECTION=new String[] {Contacts._ID, Contacts.DISPLAY_NAME, Phone.NUMBER};
Cursor pCur = cr.query(Phone.CONTENT_URI, PROJECTION, Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
This eliminates the per-row sub-query.
Using a Cursor
is a great approach for this problem. To get retrieve information from a specific position, you can use Cursor.moveToPosition(int position)
. Then you can access any field of the Cursor
, in this case a String
, using Cursor.getString(int columnIndex)
.
Take a look at the Cursor documentation for more details.
The best part about this approach is that you can implement a CursorLoader to do the background data retrieval for you. It also automatically handles repopulating your ListView
on data changes, orientation changes, etc. Check out this great tutorial for more explanation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With