Fetching more than 10000 contacts from android device

2.1k views Asked by At

I want to retrieve >10000 contacts from the android device. To fetch that much contact it takes about 8-10 min. Is there any other possible way to do this. I have implemented a method its working fine but when it comes to large number of contacts it taking it time to fetch the contacts.

 ContentResolver cr = getActivity().getApplication().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));
            if (Integer.parseInt(cur.getString(cur.getColumnIndex(
                    ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
                Cursor pCur = cr.query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
                        new String[]{id}, null);
                while (pCur.moveToNext()) {
                    int phoneType = pCur.getInt(pCur.getColumnIndex(
                            ContactsContract.CommonDataKinds.Phone.TYPE));
                    String phoneNumber = pCur.getString(pCur.getColumnIndex(
                            ContactsContract.CommonDataKinds.Phone.NUMBER));

                    phoneNumber = phoneNumber.replace(" ","");
                    phoneNumber = phoneNumber.replace("-","");

                    boolean addNumber = stringCheck(phoneNumber,symbols);

                    if (!addNumber){

                        if (phoneNumber.length() == 10){
                            addContact(phoneNumber,phoneType,name);
                        }else if (phoneNumber.length() == 11){
                            phoneNumber = phoneNumber.substring(1);
                            addContact(phoneNumber,phoneType,name);

                        }else if (phoneNumber.length() == 12){
                            phoneNumber = phoneNumber.substring(2);
                            addContact(phoneNumber,phoneType,name);

                        }else if (phoneNumber.length() == 13){
                            phoneNumber = phoneNumber.substring(3);
                            addContact(phoneNumber,phoneType,name);
                        }

                    }

                }
                pCur.close();
            }
        }
    }
4

There are 4 answers

0
marmor On BEST ANSWER

If 900 out of the 1000 contacts have phone numbers, you're currently querying the DB 901 times, you can reduce it to only two queries:

  1. Give me all contacts information
  2. Give me all phone numbers

Then you use the contact-id field on both to match the phone to the right contacts.

Also, as noted in other answers, you really should add projection to all your queries to improve performance.

Another improvement you can make is to avoid runtime cur.getColumnIndex() calls, if you have a projection, you should already know the index - so use it hard-coded

Map<Long, List<String>> phones = new HashMap<>();
ContentResolver cr = getActivity().getApplication().getContentResolver();

// First build a mapping: contact-id > list of phones
Cursor cur = cr.query(Phone.CONTENT_URI, new String[] { Phone.CONTACT_ID, Phone.Number }, null, null, null);
while (cur != null && cur.moveToNext()) {
   long contactId = cur.getLong(0);
   String phone = cur.getString(1);
   List list;
   if (phones.contains(contactId)) {
      list = phones.get(contactId);
   } else {
      list = new ArrayList<String>();
      phones.put(contactId, list);
   }
   list.add(phone);
}
cur.close();

// Next query for all contacts, and use the phones mapping
cur = cr.query(Contacts.CONTENT_URI, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
while (cur != null && cur.moveToNext()) {
   long id = cur.getLong(0);
   String name = cur.getString(1);
   List<String> contactPhones = phones.get(id);
   addContact(id, name, contactPhones);
}
1
Sanat Pandey On

Keep your fetching process in doInBackground method of AyncTask and then display it. And get only those info which is required first, eg, Contact Name and ID.

refer this ans for more clarification: Fetching a large number of contacts

2
Awadesh On

In order to fetch large number of contacts you must be fetching the contacts in the form of pages by using rest API. For example page size of contacts is 100.

One possible approach:

If you are showing the contacts in the listview then you can fetch the data while user is scrolling the list. For that You have to set the threshold position of the list i.e. 80, So when user reaches at 80th position while scrolling you can hit your rest API for next page to fetch the new contacts and add those contacts in the listview.

From your comments i can see you want all the contacts in order to move forward.For this you can start an intent service when app is launched. This service will fetch all the contacts and store them. You can use them as per your needs

1
Nas On

Here some optimization for speed up

String[] select = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};

Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, select, null, null, null);

String[] selectOnly = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE};

Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        selectOnly,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
                        new String[]{id}, null);

Do your number check, length check in server side if possible. Do it in Async task.