Android contacts Display Name and Phone Number(s) in single database query?

I’m trying to obtain a list of contacts from the native database with their Display Name and Phone Number (any or all). There are many methods for obtaining this information with several queries to the phone’s database, but this introduces considerable overhead.

Here is the query I’ve been working on, but it results in

  • How to show one layout on top of the other programmatically in my case?
  • Android Intent Cannot resolve constructor
  • Need to post an image to Tumblr blog in android
  • Error in Android's clearCheck() for RadioGroup?
  • Android - Independent Fragment UI testing tool
  • Error in building project in Android Studio
  • Uri uri                = ContactsContract.Contacts.CONTENT_URI;
    String[] projection    = new String[] { ContactsContract.Contacts._ID,
                                            ContactsContract.Contacts.DISPLAY_NAME,
                                            ContactsContract.CommonDataKinds.Phone.NUMBER};
    String selection       = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'";
    String[] selectionArgs = null;
    String sortOrder       = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
    
    Cursor people          = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
    
    int index_id    = people.getColumnIndex(ContactsContract.Contacts._ID);
    int indexName   = people.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
    int indexNumber = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    
    people.moveToFirst();
    do {
        String _id    = people.getString(index_id);
        String name   = people.getString(indexName);
        String number = people.getString(indexNumber);
        // Do work...
    } while (people.moveToNext());
    

    And here’s the resulting error.

    E/AndroidRuntime(21549): Caused by: java.lang.IllegalArgumentException: Invalid column data1
    E/AndroidRuntime(21549):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:144)
    E/AndroidRuntime(21549):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:114)
    E/AndroidRuntime(21549):    at android.content.ContentProviderProxy.bulkQueryInternal(ContentProviderNative.java:372)
    E/AndroidRuntime(21549):    at android.content.ContentProviderProxy.query(ContentProviderNative.java:408)
    E/AndroidRuntime(21549):    at android.content.ContentResolver.query(ContentResolver.java:264)
    

    Thoughts? I believe a join may be needed to get all the columns in a single query.

    Related posts:

    ActionBarSherlock - The type android.support.v4.app.Fragment cannot be resolved. It is indirectly re...
    Now that SSLSocketFactory is deprecated on Android, what would be the best way to handle Client Cert...
    How to map Enum in GreenDAO
    How to test Menu
    Android: Howto send requests to the Google API when a user pauses typing?
    Android : Multiple Actions on a List View - Focus Issue
  • How to integrate Matlab code library with Android?
  • Get speed of a onTouch ACTION_MOVE event in Android
  • Android multiple ImageView moving on touch
  • Running the new Intel emulator for Android
  • Android - startActivityForResult immediately triggering onActivityResult
  • Change widget visibility on click
  • 3 Solutions collect form web for “Android contacts Display Name and Phone Number(s) in single database query?”

    Try this code:

    Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection    = new String[] {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                    ContactsContract.CommonDataKinds.Phone.NUMBER};
    
    Cursor people = getContentResolver().query(uri, projection, null, null, null);
    
    int indexName = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
    int indexNumber = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    
    if(people.moveToFirst()) {
        do {
            String name   = people.getString(indexName);
            String number = people.getString(indexNumber);
            // Do work...
        } while (people.moveToNext());
    }
    

    The contacts API is extremly tricky and has several implicit joins.

    Read the ContactContract and ContactsProvider2 if you can afford the time.

    What do you want? The tables are chained like this:

    • Contact 1–* Raw Contact
    • Raw Contact 1–* Phone Number (data table)

    The API works like this: you select the bottom-most element (a phone number) and implicit join to the topmost element (contact).

    You want to use the PHONE URI case (ContactsProvider2 / line 4377). This should select all phone numbers and join up to the contact.

    Combine the PHONE uri with some UI magic (for grouping), request the DISPLAY_NAME and the PHONE number (DATA1?) and you should be able to solve the problem.

    Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in the SDK variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.

    private String displayName(Uri contactUri) {
            HashSet detail = ContactDetail.getInstance().getContactArray();
            Log.d("ITEM", contactUri.toString());
            String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
            Cursor queryCursor = getActivity().getContentResolver()
                    .query(contactUri, null, null, null, null);
            queryCursor.moveToFirst();
            String name = queryCursor.getString(queryCursor.getColumnIndex("display_name"));
            String id = queryCursor.getString(
                    queryCursor.getColumnIndex(ContactsContract.Contacts._ID));
    
            if (Integer.parseInt(queryCursor.getString(queryCursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
                Cursor pCur = getActivity().getContentResolver().query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
                        new String[]{id}, null);
                while (pCur.moveToNext()) {
                    String number = pCur.getString(pCur.getColumnIndex("data1"));
                    Log.d("Contact Name: ", number);
                }
                pCur.close();
            }
    
    
            return name;
        }
    

    Perform a second query against the Android contacts SQLite database. The phone numbers are queried against the URI stored in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. The contact ID is stored in the phone table as ContactsContract.CommonDataKinds.Phone.CONTACT_ID and the WHERE clause is used to limit the data returned.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.