Android Reading Phone Contacts Example

In this tutorial we are going to show how to read phone contacts which includes Phone Numbers and Email IDs display them in ListView. Show counter and progress bar while fetching the contacts form the device. To demonstrate this example I have used two of our previous tutorials.

  1. Android ListView Example
  2. Progress Dialog – Android Example

See flowing Steps :

  1. Declare READ_CONTACTS permission in the AndroidManifest.xml file.
  2. Create activity_main.xml layout file with one ListView.
  3. Create simple custom layout for list item with only one TextView widget.
  4. In MainActivity.java, display progress bar, read contacts in a separate thread, attach the adapter to the ListView and then cancel the progress bar.
  5. Use ProgressDialog and update the progress message with the current reading count of contacts.
  6. Permissions should be handled at runtime for Android versions from Marshmallow and above

Note: In this tutorial I have used Thread for the long running contacts fetching operation. This can be done using AsyncTask also.
You have to declare android.permission.READ_CONTACTS permission in the manifest file.
Handler and runOnUiThread are used to update the UI thread.

1. Manifest file

2. Activity layout file

I have used a separate layout file for the list item, you can use the default android layout file android.R.layout.simple_list_item_1 and point to the TextView widget with id as android.R.id.text1

3. Main Activity code
In this, we are using an int variable named counter to update the progress bar to notify the user about the number of contacts fetched. Display progress bar read contacts in a separate thread, attach the adapter to the ListView and then cancel the progress bar.

4. Demonstration

Read Contacts - Progress bar
Read Contacts – Progress bar
Read Contacts - list view
Read Contacts – list view

Comments

  1. The contacts gets repeated and more empty spaces added between the contacts..can you help me with that..

    1. Norman Younghusband

      Instead of using the following function
      while (phoneCursor.moveToNext()) {
      phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
      output.append(“\n Phone number:” + phoneNumber);
      }
      Use this :
      while (phoneCursor.moveToNext()) { //I changed the function because many numbers(same) were coming with an extra hyphen
      phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
      if(phoneNumber.indexOf(‘-‘)<0) {
      output.append("\n Phone number:" + phoneNumber);
      break;
      }
      else
      continue;
      }

      1. Vinothkumar Arputharaj

        Hi Norman,

        Thanks for sharing the code snippet.

  2. Mark Joshua Antony Pastrana

    We followed the steps. I got this message “Unfortunately, My Application has stopped.”..

    1. Vinothkumar Arputharaj

      Can you post the stacktrace for reference. If you are testing the app in Marshmallow, you have to handle new Permissions API changes.

      1. hello Mr.Vinothkumar Arputharaj Can you help me turtorial continues with this turtorial (Android Reading Phone Contacts Example) then asynch to server with php and database.msql to. Thank you for your support

  3. thank you very much for that example. i imported the project as new project into android studio and it runs from beginning.
    good explained.
    So thanks.

  4. Thank you very much for the code sample!

  5. Works for me, thanks mate.

  6. Afzal Hossain

    Would please add the code for retrieving birthday also?

    1. Vinothkumar Arputharaj

      Hi Afzal,

      You have to add the DOB related columns in your query.

      Try this snippet and add it in line number 163.

      String columns[] = {
      ContactsContract.CommonDataKinds.Event.START_DATE,
      ContactsContract.CommonDataKinds.Event.TYPE,
      ContactsContract.CommonDataKinds.Event.MIMETYPE,
      };

      String where = ContactsContract.CommonDataKinds.Event.TYPE + “=” + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY +
      ” and ” + ContactsContract.CommonDataKinds.Event.MIMETYPE + ” = ‘” + ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE + “‘ and ” + ContactsContract.Data.CONTACT_ID + ” = ” + contact_id;

      String[] selectionArgs = null;
      String sortOrder = ContactsContract.Contacts.DISPLAY_NAME;

      Cursor birthdayCur = contentResolver.query(ContactsContract.Data.CONTENT_URI, columns, where, selectionArgs, sortOrder);
      Log.d(“BDAY”, birthdayCur.getCount()+””);
      if (birthdayCur.getCount() > 0) {
      while (birthdayCur.moveToNext()) {
      String birthday = birthdayCur.getString(birthdayCur.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE));
      output.append(“Birthday :” + birthday);
      Log.d(“BDAY”, birthday);
      }
      }
      birthdayCur.close();

      Snippet reference: https://stackoverflow.com/a/10782519/403255

  7. Swapna Prakash

    My application is crashing after reading 1,410 contacts… I need to access 3000 contacts. Please, can anyone help me!

  8. Swapna Prakash

    I have 3000 contacts on my phone when I try to access after 1417 contacts my app is crashing… Please, can anyone help me! What needs to do?

    1. Vinothkumar Arputharaj

      Hi Swapna,
      If you can share your error trace, I could help you.

      1. Swapna Prakash

        I have modified few things…

        public void getContacts() {
        contactList = new ArrayList();
        Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
        String _ID = ContactsContract.Contacts._ID;
        String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
        String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;

        Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
        String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
        StringBuffer output;

        Context applicationContext = NextActivity.getContextOfApplication();
        ContentResolver contentResolver = applicationContext.getContentResolver();

        cursor = contentResolver.query(CONTENT_URI, null,null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+” ASC”);

        if (cursor.getCount() > 0 ) {

        counter = 0;
        while (cursor.moveToNext() ) {
        output = new StringBuffer();

        // Update the progress message
        updateBarHandler.post(new Runnable() {
        public void run() {
        pDialog.setMessage(“Reading contacts : “+ counter++ +”/”+cursor.getCount());
        }
        });

        String contact_id = cursor.getString(cursor.getColumnIndex( _ID ));
        name = cursor.getString(cursor.getColumnIndex( DISPLAY_NAME ));
        int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex( HAS_PHONE_NUMBER )));
        if ((hasPhoneNumber > 0)) {
        Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, Phone_CONTACT_ID + ” = ?”, new String[]{contact_id}, null);

        while (phoneCursor.moveToNext()) { //I changed the function because many numbers(same) were coming with an extra hyphen
        phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
        if ((phoneNumber.indexOf(‘-‘) < 0)) {

        contact = new PhoneContact();
        contact.setName(name);
        contact.setPhoneNumber(phoneNumber);
        contactArrayList.add(contact);

        break;
        } else
        continue;
        }
        }
        }
        // ListView has to be updated using a ui thread
        getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
        adapter =new ReadContactAdapter(getActivity(),contactArrayList);
        mListView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
        }
        });

        // Dismiss the progressbar after 500 millisecondds
        updateBarHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
        pDialog.cancel();
        }
        }, 500);
        }

        }

      2. Swapna Prakash

        public void getContacts() {
        contactList = new ArrayList();
        Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
        String _ID = ContactsContract.Contacts._ID;
        String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
        String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;

        Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
        String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
        StringBuffer output;

        Context applicationContext = NextActivity.getContextOfApplication();
        ContentResolver contentResolver = applicationContext.getContentResolver();

        cursor = contentResolver.query(CONTENT_URI, null,null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+” ASC”);

        if (cursor.getCount() > 0 ) {

        counter = 0;
        while (cursor.moveToNext() ) {
        output = new StringBuffer();

        // Update the progress message
        updateBarHandler.post(new Runnable() {
        public void run() {
        pDialog.setMessage(“Reading contacts : “+ counter++ +”/”+cursor.getCount());
        }
        });

        String contact_id = cursor.getString(cursor.getColumnIndex( _ID ));
        name = cursor.getString(cursor.getColumnIndex( DISPLAY_NAME ));
        int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex( HAS_PHONE_NUMBER )));
        if ((hasPhoneNumber > 0)) {
        Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, Phone_CONTACT_ID + ” = ?”, new String[]{contact_id}, null);

        while (phoneCursor.moveToNext()) { //I changed the function because many numbers(same) were coming with an extra hyphen
        phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
        if ((phoneNumber.indexOf(‘-‘) < 0)) {

        contact = new PhoneContact();
        contact.setName(name);
        contact.setPhoneNumber(phoneNumber);
        contactArrayList.add(contact);

        break;
        } else
        continue;
        }
        }
        }
        // ListView has to be updated using a ui thread
        getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
        adapter =new ReadContactAdapter(getActivity(),contactArrayList);
        mListView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
        }
        });

        // Dismiss the progressbar after 500 millisecondds
        updateBarHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
        pDialog.cancel();
        }
        }, 500);
        }

        }

      3. Swapna Prakash

        if (cursor.getCount() > 0 ) {

        counter = 0;
        while (cursor.moveToNext() ) {
        output = new StringBuffer();

        // Update the progress message
        updateBarHandler.post(new Runnable() {
        public void run() {
        pDialog.setMessage(“Reading contacts : “+ counter++ +”/”+cursor.getCount());
        }
        });

        String contact_id = cursor.getString(cursor.getColumnIndex( _ID ));
        name = cursor.getString(cursor.getColumnIndex( DISPLAY_NAME ));
        int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex( HAS_PHONE_NUMBER )));
        if ((hasPhoneNumber > 0)) {
        Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, Phone_CONTACT_ID + ” = ?”, new String[]{contact_id}, null);

        while (phoneCursor.moveToNext()) { //I changed the function because many numbers(same) were coming with an extra hyphen
        phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
        if ((phoneNumber.indexOf(‘-‘) < 0)) {

        contact = new PhoneContact();
        contact.setName(name);
        contact.setPhoneNumber(phoneNumber);
        contactArrayList.add(contact);

        break;
        } else
        continue;
        }
        }
        }
        // ListView has to be updated using a ui thread
        getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
        adapter =new ReadContactAdapter(getActivity(),contactArrayList);
        mListView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
        }
        });

        // Dismiss the progressbar after 500 millisecondds
        updateBarHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
        pDialog.cancel();
        }
        }, 500);
        }

        1. Swapna Prakash

          My application is crashing while fetching… Above I have attached my code

          1. Vinothkumar Arputharaj

            It’s good that you have shared your code snippet. If you can share the error traces from LOGCAT, or error causing method or line number, it would be easy for me to solve it.

          2. java.lang.NullPointerException
            In the line.. while (phoneCursor.moveToNext())

          3. java.lang.NullPointerException
            In the line..
            while (phoneCursor.moveToNext())

          4. Vinothkumar Arputharaj

            I couldn’t recreate this NPE error. If you can share the full stack trace. I can debug. You may not be able to post huge content in the comment section. You can send it to vino4all@gmail.com

  9. Mayur Dhanrajani

    Hey how to run this app in Marshmallow ?

    1. Vinothkumar Arputharaj

      The code is updated in the article. Please refer MainActivity.java section for runtime permission check.

  10. Swapna Prakash

    You need to check runtime permissions

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(getActivity(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_PERMISSION);
    //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
    } else {
    // Android version is lesser than 6.0 or the permission is already granted.

    // Since reading contacts takes more time, let’s run it on a separate thread.
    new Thread(new Runnable() {
    @Override
    public void run() {
    getContacts();
    }
    }).start();
    }

    1. Swapna Prakash

      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
      if (requestCode == REQUEST_PERMISSION) {
      if (grantResults.length != 0) {
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
      getContacts();
      } else {
      // getActivity().finish();
      }
      }
      }
      }

      1. Vinothkumar Arputharaj

        Hi Swapna,

        You are right. I have updated the code snippet in the article content.

        Thanks for the reply.

        1. Swapna Prakash

          Hi Vinothkumar,
          Welcome… Yesterday I asked doubt know… Please need help

  11. hi In my condition its not working its progress dialog showing reading your contacts after some reading full contact , nothing showing and app crashed please help me out.

    1. java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.widget.TextView.setText(java.lang.CharSequence)’ on a null object reference
      at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:399)
      at android.widget.ArrayAdapter.getView(ArrayAdapter.java:369)
      at android.widget.AbsListView.obtainView(AbsListView.java:2346)
      at android.widget.ListView.measureHeightOfChildren(ListView.java:1281)
      at android.widget.ListView.onMeasure(ListView.java:1188)
      at android.view.View.measure(View.java:18811)
      at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:716)
      at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:462)
      at android.view.View.measure(View.java:18811)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
      at android.view.View.measure(View.java:18811)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
      at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
      at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
      at android.view.View.measure(View.java:18811)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
      at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2645)
      at android.view.View.measure(View.java:18811)
      at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2127)
      at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1243)
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1479)
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1134)
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6050)
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
      at android.view.Choreographer.doCallbacks(Choreographer.java:672)
      at android.view.Choreographer.doFrame(Choreographer.java:608)
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
      at android.os.Handler.handleCallback(Handler.java:742)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:154)
      at android.app.ActivityThread.main(ActivityThread.java:5529)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)

    2. Vinothkumar Arputharaj

      Hi,

      This means that the textView is null. This is mostly because the textview is not referenced correctly. Can you post your code snippets.

      1. JIT allocated 71KB for compiled code of void android.widget.TextView.(android.content.Context, android.util.AttributeSet, int, int)
        11-25 22:45:00.304 8744-8750/oss.osss I/zygote: Compiler allocated 4MB to compile void android.widget.TextView.(android.content.Context, android.util.AttributeSet, int, int)

        1. public class MyContactList extends Activity {
          private static final int REQUEST_READ_CONTACTS = 444;
          private ListView mListView;
          private TextView text1;
          private ProgressDialog pDialog;
          private Handler updateBarHandler;
          ArrayList contactList;
          Cursor cursor;
          int counter;

          /**
          *
          * @param savedInstanceState
          */
          @Override
          public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_my_contact_list);
          pDialog = new ProgressDialog(MyContactList.this);
          pDialog.setMessage(“Reading contacts…”);
          pDialog.setCancelable(false);
          pDialog.show();
          mListView = (ListView) findViewById(R.id.list);
          updateBarHandler = new Handler();
          // Since reading contacts takes more time, let’s run it on a separate thread.
          new Thread(new Runnable() {
          @Override
          public void run() {
          getContacts();
          }
          }).start();
          // Set onclicklistener to the list item.
          mListView.setOnItemClickListener(new OnItemClickListener() {
          @Override
          public void onItemClick(AdapterView parent, View view,
          int position, long id) {
          //TODO Do whatever you want with the list data
          Toast.makeText(getApplicationContext(), “item clicked : \n” + contactList.get(position), Toast.LENGTH_SHORT).show();
          }
          });
          }

          /**
          *
          * @return
          */
          private boolean mayRequestContacts() {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
          return true;
          }
          if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
          return true;
          }
          if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
          requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
          } else {
          requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
          }
          return false;
          }

          /**
          * Callback received when a permissions request has been completed.
          */
          @Override
          public void onRequestPermissionsResult(int requestCode, String[] permissions,
          int[] grantResults) {
          if (requestCode == REQUEST_READ_CONTACTS) {
          if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
          getContacts();
          }
          }
          }

          1. Vinothkumar Arputharaj

            The problem is with the layout set in ArrayAdapter. Please refer line 208. You will get this error if the , expected id of the textview is not available

          2. Hi
            I have changed it And I’m testing it on emulator my progress dialog is running means its on infinity mode
            here my adapter code

            >>>>>>>>>>
            runOnUiThread(new Runnable() {
            @Override
            public void run() {
            ArrayAdapter adapter = new ArrayAdapter
            (getApplicationContext(),
            android.R.layout.simple_list_item_1, android.R.id.text1, contactList);
            mListView.setAdapter(adapter);
            }
            });

          3. Vinothkumar Arputharaj

            Check the line 218. You have to cancel the dialog once your job is done.

            pDialog.cancel();

  12. * @param savedInstanceState
    */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_contact_list);
    pDialog = new ProgressDialog(MyContactList.this);
    pDialog.setMessage(“Reading contacts…”);
    pDialog.setCancelable(false);
    pDialog.show();
    mListView = (ListView) findViewById(R.id.list);
    updateBarHandler = new Handler();
    // Since reading contacts takes more time, let’s run it on a separate thread.
    new Thread(new Runnable() {
    @Override
    public void run() {
    getContacts();
    }
    }).start();
    // Set onclicklistener to the list item.
    mListView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView parent, View view,
    int position, long id) {
    //TODO Do whatever you want with the list data
    Toast.makeText(getApplicationContext(), “item clicked : \n” + contactList.get(position), Toast.LENGTH_SHORT).show();
    }
    });
    }

  13. /**
    *
    * @return
    */
    private boolean mayRequestContacts() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
    return true;
    }
    if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
    return true;
    }
    if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
    requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
    } else {
    requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
    }
    return false;
    }

    /**
    * Callback received when a permissions request has been completed.
    */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
    int[] grantResults) {
    if (requestCode == REQUEST_READ_CONTACTS) {
    if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    getContacts();
    }
    }
    }

  14. Thank you very much for example.
    Very Good Explaination.

  15. Swapna Prakash

    Hi Vinothkumar Arputharaj,
    I need to store the phone number in the format country code space 5 digit space 5 digit eg: +91 xxxxx xxxxx. How to do this Please need help

  16. I am trying to implement this code in AsyncTask but application crash , can you help me?

    1. Vinothkumar Arputharaj

      Hi Arjit,

      Can you share the exact error.

      You can replace new Thread() implementation with AsyncTask

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">