1

I have read all the phone contacts from the device and set them to an adapter for the AutoCompleteTextView. The function that does this is:

private void storeContactsToArrayList() {
    Log.d("In ", "storeContactsToArrayList() called");

    List<Contact> contactList = new ArrayList<>();

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

    if ((cur != null ? cur.getCount() : 0) > 0) {
        while (cur != null && cur.moveToNext()) {
            String id = cur.getString(
                    cur.getColumnIndex(ContactsContract.Contacts._ID));
            String name = cur.getString(cur.getColumnIndex(
                    ContactsContract.Contacts.DISPLAY_NAME));

            if (cur.getInt(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()) {
                    String phoneNo = pCur.getString(pCur.getColumnIndex(
                            ContactsContract.CommonDataKinds.Phone.NUMBER));
//                        Log.i("GOT", "Name: " + name);
//                        Log.i("GOT", "Phone Number: " + phoneNo); //working
                    //To our POJO
                    Contact contact = new Contact();
                    contact.setName(name);
                    contact.setPhoneNumber(phoneNo);

                    contactList.add(contact);

                }
                pCur.close();
            }
            ArrayAdapter<Contact> contactsArrayAdapter =
                    new ArrayAdapter<Contact>(this, android.R.layout.simple_list_item_1, contactList);

            //setting this adapter to our autocompleteTextView userInput
            userInput.setAdapter(contactsArrayAdapter);
        }
    }
    if(cur!=null){
        cur.close();
    }
}

However when I ran the code, I realized that the function takes quite some time to execute, which seems poor. From what I know I should be using an inner class like AdapterTask extends Async Task to do the same thing but asynchronously without blocking my main UI thread. I tried doing so, but I could not. Please suggest me if there are any other ways of doing the same thing wihtout using AsyncTask, or if AsyncTask is the way to go, how can I achieve the thing that the above function is doing using AsyncTask. Thanks.

ravi
  • 743
  • 4
  • 26
  • see [this](https://stackoverflow.com/a/19860624/2252830) - inside `rawQuery` you should use `CommonDataKinds.Phone#CONTENT_FILTER_URI` (or `PhoneLookup#CONTENT_FILTER_URI`) – pskink Dec 26 '17 at 09:03

2 Answers2

2

Create a separate class for background task and communicate with a listener(And interface). Below is and example Modify it as per your need.

 public class FetchContacts extends AsyncTask<Void, Void, List> {
    private Context activity;
    private OnContactFetchListener listener;
    public FetchContacts(Context context, OnContactFetchListener listener) {
        activity = context;
        this.listener = listener;
    }
    @Override
    protected List doInBackground(Void... params) {
        List<Contact> contactList = new ArrayList<>();
        // get Contacts here
        return contactList;
    }

    @Override
    protected void onPostExecute(List list) {
        super.onPostExecute(list);
        if(listener!=null){
            listener.onContactFetch(list);
        }
    }

    public interface OnContactFetchListener {
        void onContactFetch(List  list);
    }
}

Can be call as .

  new FetchContacts(activity, new FetchContacts.OnContactFetchListener() {
                @Override
                public void onContactFetch(List contacts) {
                    // Here you will get the contacts
                }
            }).execute();
ADM
  • 16,256
  • 11
  • 37
  • 69
  • Thanks, what parameters would I pass in `doInBackground()`, I tried doing so by passing the Cursor as parameter but it did not let me call `cursorObject.moveToNext()` or any other methods on the cursor object. – ravi Dec 26 '17 at 08:44
  • No need to pass any parameter in `doInBackground()` in this case . Just paste all code inside `doInBackground()` and return `contactList`. – ADM Dec 26 '17 at 09:07
  • Hey Thank you very much, I did as you suggested and the app now seems to open up much faster without blocking the main UI thread, as it did earlier. Thanks. – ravi Dec 26 '17 at 11:19
  • Can not upvote, but I did accept. Thank you very much – ravi Dec 26 '17 at 11:28
-1

Like @ADM suggested. Create a separate class, not an inner class. FetchContacts.java

public class FetchContacts extends AsyncTask<Void, Void, List> {
private Context activity;
private OnContactFetchListener listener;

public FetchContacts(Context context, OnContactFetchListener listener) {
    activity = context;
    this.listener = listener;
}

@Override
protected List doInBackground(Void... voids) {
    List<Contact> contactList = new ArrayList<>();
    // get Contacts here

    ContentResolver cr = activity.getContentResolver();
    Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
            null, null, null, null);

    if ((cur != null ? cur.getCount() : 0) > 0) {
        while (cur != null && cur.moveToNext()) {
            String id = cur.getString(
                    cur.getColumnIndex(ContactsContract.Contacts._ID));
            String name = cur.getString(cur.getColumnIndex(
                    ContactsContract.Contacts.DISPLAY_NAME));

            if (cur.getInt(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()) {
                    String phoneNo = pCur.getString(pCur.getColumnIndex(
                            ContactsContract.CommonDataKinds.Phone.NUMBER));
//                        Log.i("GOT", "Name: " + name);
//                        Log.i("GOT", "Phone Number: " + phoneNo); //working
                    //To our POJO
                    Contact contact = new Contact();
                    contact.setName(name);
                    contact.setPhoneNumber(phoneNo);

                    contactList.add(contact);

                }
                pCur.close();
            }
        }
    }
    if (cur != null) {
        cur.close();
    }
    return contactList;
}

@Override
protected void onPostExecute(List list) {
    super.onPostExecute(list);
    if (listener != null) {
        listener.onContactFetch(list);
    }
}

public interface OnContactFetchListener {
    void onContactFetch(List list);
}
}

And call the class, set the list of contacts to ArrayAdapter and the arrayadapter to the autocomplete textview as:

new FetchContacts(MainActivity.this, new FetchContacts.OnContactFetchListener() {
        @Override
        public void onContactFetch(List contacts) {
            // Here you will get the contacts
            ArrayAdapter<Contact> contactArrayAdapter = new ArrayAdapter<Contact>(MainActivity.this,
                    android.R.layout.simple_list_item_1, contacts);
            userInput.setAdapter(contactArrayAdapter); //userInput is our AutoCompleteTextView

        }
    }).execute();
ravi
  • 743
  • 4
  • 26