Android ContactsContract with AutocompleteTextview too slow

584 views Asked by At

Am trying to use the ContactsProvider with my AutoCompleteTextview using a method that fetches the data (name and phone number) and stores them in a list. As expected, this method will always take time to complete as am calling the method in the onCreateView method of my Fragment class.

This is the method:

...
ArrayList<String> phoneValues;
ArrayList<String> nameValues;
...

private void readContactData() {

    try {

        /*********** Reading Contacts Name And Number **********/

        String phoneNumber = "";
        ContentResolver contentResolver = getActivity()
                .getContentResolver();

        //Query to get contact name

        Cursor cursor = contentResolver
                .query(ContactsContract.Contacts.CONTENT_URI,
                        null,
                        null,
                        null,
                        null);

        // If data data found in contacts
        if (cursor.getCount() > 0) {

            int k=0;
            String name = "";

            while (cursor.moveToNext())
            {

                String id = cursor
                        .getString(cursor
                                .getColumnIndex(ContactsContract.Contacts._ID));
                name = cursor
                        .getString(cursor
                                .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

                //Check contact have phone number
                if (Integer
                        .parseInt(cursor
                                .getString(cursor
                                        .getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
                {

                    //Create query to get phone number by contact id
                    Cursor pCur = contentResolver
                            .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                    null,
                                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID
                                            + " = ?",
                                    new String[] { id },
                                    null);
                    int j=0;

                    while (pCur
                            .moveToNext())
                    {
                        // Sometimes get multiple data
                        if(j==0)
                        {
                            // Get Phone number
                            phoneNumber =""+pCur.getString(pCur
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

                            // Add contacts names to adapter
                            autocompleteAdapter.add(name);

                            // Add ArrayList names to adapter
                            phoneValues.add(phoneNumber.toString());
                            nameValues.add(name.toString());

                            j++;
                            k++;
                        }
                    }  // End while loop
                    pCur.close();
                } // End if

            }  // End while loop

        } // End Cursor value check
        cursor.close();


    } catch (Exception e) {
        Log.i("AutocompleteContacts","Exception : "+ e);
    }


}

Am sure there is a better way to accomplish this, but this method works and the suggestions are presented when I type into the AutocompleteTextview. Am just worried about the time it takes. How can I accomplish this without populating an ArrayList? I have looked at this question: Getting name and email from contact list is very slow and applied the suggestions in the answer to my code, but now nothing is suggested when I type.How can I improve the performance of my current code?

2

There are 2 answers

3
Anusha Harish On

This is how i have implemented AutoCompleteTextView and it works fine for me ..

  final AutoCompleteTextView act=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
         ArrayList<String> alContacts = new ArrayList<String>();
         ArrayList<String> alNames= new ArrayList<String>();

ContentResolver cr = this.getContentResolver(); //Activity/Application android.content.Context
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if(cursor.moveToFirst())
{

    do
    {
        String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));

        if(Integer.parseInt(cursor.getString(cursor.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()) 
            {
                String contactNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                String contactName=pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                alNames.add(contactName);
                alContacts.add(contactNumber);
                break;
            }
            pCur.close();
        }

    } while (cursor.moveToNext()) ;
}


String[] array=new String[alNames.size()];
array=(String[]) alNames.toArray(array);
ArrayAdapter<String> myArr= new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,array);
act.setAdapter(myArr);
act.setThreshold(1);
8
Ojonugwa Jude Ochalifu On

I got rid of the slow response by placing the method inside an AsynTask.

 public class AutocompleteAsyncTask extends AsyncTask<Void, Void, Void> {


    public Void doInBackground(Void...params) {

        try {

            /*********** Reading Contacts Name And Number **********/

            String phoneNumber = "";
            ContentResolver contentResolver = getActivity()
                    .getContentResolver();

            //Query to get contact name

            Cursor cursor = contentResolver
                    .query(ContactsContract.Contacts.CONTENT_URI,
                            null,
                            null,
                            null,
                            null);

            // If data data found in contacts
            if (cursor.getCount() > 0) {

                int k=0;
                String name = "";

                while (cursor.moveToNext())
                {
            //...Rest of the same code as above

and then calling this in my onCreateView():

public View onCreateView(LayoutInflater inflater, ViewGroup container, 

  Bundle savedInstanceState) {
...
  new AutocompleteAsyncTask().execute();
   return rootView;
}

Now the task of inflating my view and fetching the data are separated into two different threads.

The CursorLoader option mentioned by Eugen Pechanec is kinda the best option, so I'll update this answer with that option when I can.