Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get contacts performance issue

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:

  • I don't know how to get item at specific position.
  • each cursor has different columns.

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;
}
like image 873
oshai Avatar asked Jun 06 '12 19:06

oshai


2 Answers

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.

like image 65
CommonsWare Avatar answered Sep 26 '22 01:09

CommonsWare


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.

like image 33
jmhend Avatar answered Sep 24 '22 01:09

jmhend