0

in my app, you select certain contacts which will then populate their own list within the app. What I do is pass the contact IDs from a selection activity back to my main. When trying to populate that list, I get an error. Below is both. If you can please tell me the right way to word this sql query, that'd be fantastic.

Code:

private void getStaffContacts(Context context, ArrayList<String> contact_ids) {

    Uri uri = ContactsContract.Contacts.CONTENT_URI;
    String[] projection = null;
    String selection = ContactsContract.Contacts._ID + "=?";
    String[] selectionArgs = getContactSelectionArgs(contact_ids);
    String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;

    ContentResolver cr = context.getContentResolver();
    Cursor cursor = cr.query(uri, projection, selection, selectionArgs,
            sortOrder);

    while (cursor != null && cursor.moveToNext()) {

        String id = cursor.getString(cursor
                .getColumnIndex(ContactsContract.Contacts._ID));
        Log.e("Debug", id);

        ContactItem contactItem = new ContactItem();

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

        Uri imageUri = ContentUris.withAppendedId(
                ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));

        contactItem.set_id(id);
        contactItem.setName(name);
        contactItem.setImageUri(imageUri);

        mStaffAdapter.add(contactItem);
    }
}

private String[] getContactSelectionArgs(ArrayList<String> contact_ids) {

    String[] namesArr = new String[contact_ids.size()];

    for (int i = 0; i < contact_ids.size(); i++) {

        namesArr[i] = contact_ids.get(i);
    }

    return namesArr;
}

Logcat:

04-17 00:30:16.242: E/ContactsFragment(3434): ActivityResult code = -1
04-17 00:30:16.503: E/AndroidRuntime(3434): FATAL EXCEPTION: main
04-17 00:30:16.503: E/AndroidRuntime(3434): java.lang.RuntimeException: Failure delivering result ResultInfo{who=android:fragment:0, request=999, result=-1, data=Intent { (has extras) }} to activity {com.psesto.workforce/com.psesto.workforce.MainActivity}: java.lang.IllegalArgumentException: Cannot bind argument at index 2 because the index is out of range.  The statement has 1 parameters.
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3319)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3362)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread.access$1100(ActivityThread.java:141)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1282)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.os.Looper.loop(Looper.java:137)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread.main(ActivityThread.java:5041)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at java.lang.reflect.Method.invokeNative(Native Method)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at java.lang.reflect.Method.invoke(Method.java:511)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at dalvik.system.NativeStart.main(Native Method)
04-17 00:30:16.503: E/AndroidRuntime(3434): Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 2 because the index is out of range.  The statement has 1 parameters.
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.content.ContentProviderProxy.query(ContentProviderNative.java:366)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.content.ContentResolver.query(ContentResolver.java:372)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.content.ContentResolver.query(ContentResolver.java:315)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at com.psesto.workforce.ContactsFragment.getStaffContacts(ContactsFragment.java:140)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at com.psesto.workforce.ContactsFragment.handlePositiveResult(ContactsFragment.java:127)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at com.psesto.workforce.ContactsFragment.onActivityResult(ContactsFragment.java:99)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.Activity.dispatchActivityResult(Activity.java:5297)
04-17 00:30:16.503: E/AndroidRuntime(3434):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)
04-17 00:30:16.503: E/AndroidRuntime(3434):     ... 11 more

UPDATE:

Per Andrew T's suggestion, I checked out that link and made some changes, but still getting a similar log. Here's the updated code and logcat. (in this example, I'm passing in 3 ids)

    private void getStaffContacts(Context context, ArrayList<String> contact_ids) {

        Uri uri = ContactsContract.Contacts.CONTENT_URI;
        String[] projection = null;
        String selection = ContactsContract.Contacts._ID 
                + "="
                + makePlaceholdersForSelection(contact_ids.size());
        String[] selectionArgs = getContactSelectionArgs(contact_ids);
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;

        ContentResolver cr = context.getContentResolver();
        Cursor cursor = cr.query(uri, projection, selection, selectionArgs,
                sortOrder);

        while (cursor != null && cursor.moveToNext()) {

            String id = cursor.getString(cursor
                    .getColumnIndex(ContactsContract.Contacts._ID));
            Log.e("Debug", id);

            ContactItem contactItem = new ContactItem();

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

            Uri imageUri = ContentUris.withAppendedId(
                    ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));

            contactItem.set_id(id);
            contactItem.setName(name);
            contactItem.setImageUri(imageUri);

            mStaffAdapter.add(contactItem);
        }
    }
private String makePlaceholdersForSelection(int length) {
        if (length < 1) {
            // It will lead to an invalid query anyway ..
            throw new RuntimeException("No placeholders");
        } else {
            StringBuilder sb = new StringBuilder(length * 2 - 1);
            sb.append("?");
            for (int i = 1; i < length; i++) {
                sb.append(",?");
            }
            return sb.toString();
        }
    }

    private String[] getContactSelectionArgs(ArrayList<String> contact_ids) {

        String[] namesArr = new String[contact_ids.size()];

        for (int i = 0; i < contact_ids.size(); i++) {

            namesArr[i] = contact_ids.get(i);
            log("i = " + i + " " + "namesArr[i] = " + namesArr[i]);
        }

        return namesArr;
    }




04-17 02:13:28.463: E/ContactsFragment(5380): ActivityResult code = -1
04-17 02:13:28.463: E/ContactsFragment(5380): i = 0 namesArr[i] = 2
04-17 02:13:28.473: E/ContactsFragment(5380): i = 1 namesArr[i] = 4
04-17 02:13:28.483: E/ContactsFragment(5380): i = 2 namesArr[i] = 3
04-17 02:13:28.593: E/AndroidRuntime(5380): FATAL EXCEPTION: main
04-17 02:13:28.593: E/AndroidRuntime(5380): java.lang.RuntimeException: Failure delivering result ResultInfo{who=android:fragment:0, request=999, result=-1, data=Intent { (has extras) }} to activity {com.psesto.workforce/com.psesto.workforce.MainActivity}: android.database.sqlite.SQLiteException: near ",": syntax error (code 1): , while compiling: SELECT times_contacted, contacts_status_updates.status AS contact_status, phonetic_name, phonetic_name_style, is_user_profile, lookup, contacts_status_updates.status_icon AS contact_status_icon, last_time_contacted, _id, display_name_source, photo_uri, photo_thumb_uri, agg_presence.chat_capability AS contact_chat_capability, photo_id, send_to_voicemail, custom_ringtone, name_raw_contact_id, photo_file_id, has_phone_number, contacts_status_updates.status_label AS contact_status_label, display_name, sort_key_alt, in_visible_group, starred, display_name_alt, sort_key, agg_presence.mode AS contact_presence, contacts_status_updates.status_res_package AS contact_status_res_package, contacts_status_updates.status_ts AS contact_status_ts FROM view_contacts LEFT OUTER JOIN agg_presence ON (_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) WHERE ((1)) AND ((_id=?,?,?))
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3319)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3362)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread.access$1100(ActivityThread.java:141)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1282)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.os.Looper.loop(Looper.java:137)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread.main(ActivityThread.java:5041)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at java.lang.reflect.Method.invokeNative(Native Method)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at java.lang.reflect.Method.invoke(Method.java:511)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at dalvik.system.NativeStart.main(Native Method)
04-17 02:13:28.593: E/AndroidRuntime(5380): Caused by: android.database.sqlite.SQLiteException: near ",": syntax error (code 1): , while compiling: SELECT times_contacted, contacts_status_updates.status AS contact_status, phonetic_name, phonetic_name_style, is_user_profile, lookup, contacts_status_updates.status_icon AS contact_status_icon, last_time_contacted, _id, display_name_source, photo_uri, photo_thumb_uri, agg_presence.chat_capability AS contact_chat_capability, photo_id, send_to_voicemail, custom_ringtone, name_raw_contact_id, photo_file_id, has_phone_number, contacts_status_updates.status_label AS contact_status_label, display_name, sort_key_alt, in_visible_group, starred, display_name_alt, sort_key, agg_presence.mode AS contact_presence, contacts_status_updates.status_res_package AS contact_status_res_package, contacts_status_updates.status_ts AS contact_status_ts FROM view_contacts LEFT OUTER JOIN agg_presence ON (_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) WHERE ((1)) AND ((_id=?,?,?))
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:181)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.content.ContentProviderProxy.query(ContentProviderNative.java:366)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.content.ContentResolver.query(ContentResolver.java:372)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.content.ContentResolver.query(ContentResolver.java:315)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at com.psesto.workforce.ContactsFragment.getStaffContacts(ContactsFragment.java:141)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at com.psesto.workforce.ContactsFragment.handlePositiveResult(ContactsFragment.java:127)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at com.psesto.workforce.ContactsFragment.onActivityResult(ContactsFragment.java:99)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.Activity.dispatchActivityResult(Activity.java:5297)
04-17 02:13:28.593: E/AndroidRuntime(5380):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)
04-17 02:13:28.593: E/AndroidRuntime(5380):     ... 11 more
Psest328
  • 6,575
  • 11
  • 55
  • 90

1 Answers1

3

The error:

java.lang.IllegalArgumentException: Cannot bind argument at index 2 because the index is out of range. The statement has 1 parameters.

The offending code:

String selection = ContactsContract.Contacts._ID + "=?";
String[] selectionArgs = getContactSelectionArgs(contact_ids);

As stated by the error, your selection query only accepts 1 value while you pass multiple values (in this case, 3).

If you want to query multiple values for 1 field, you must use WHERE IN clause.

By using a practical helper method from IN clause and placeholders:

private String makePlaceholdersForSelection(int length) {
    if (length < 1) {
        // It will lead to an invalid query anyway ..
        throw new RuntimeException("No placeholders");
    } else {
        StringBuilder sb = new StringBuilder(length * 2 - 1);
        sb.append("?");
        for (int i = 1; i < length; i++) {
            sb.append(",?");
        }
        return sb.toString();
    }
}

You can change your selection query to

String selection =
    ContactsContract.Contacts._ID
    + " IN ("
    + makePlaceholdersForSelection(contact_ids.size()) 
    + ")";

To make placeholders for WHERE IN clause, as many as the size of the ArrayList<String>.

Community
  • 1
  • 1
Andrew T.
  • 4,701
  • 8
  • 43
  • 62