androidarraylistnullpointerexceptionandroid-contactscontactscontract

Search contact name containing x


Building a device that connects to Bluetooth and retrieves contact names/numbers matching a certain "name", for example, if I search for "A - " and I have the following contacts in my phone:

[0] "A - Dad "
[1] "A - Mom"
[2] "A - Grandmother"
[3] "FirendA "

It returns the following list:

[0]
    [0] A - Dad
    [1] +33600000000
[1]
    [0] A - Mom
    [1] +33611111111
[2]
    [0] A - Grandmother
    [1] +33722222222

So this function should return an array containing the contact name and the contact number (only starting with +336 or +337 (mobile)) inside an array of all contacts matched. But so far with the code I tried it returns me a which returns me a null pointer exception:

public List<List<String>> getContacts(String name) {
        List<List<String>> out = new ArrayList<>();

        Cursor cursor = getContentResolver().query(
                android.provider.ContactsContract.Contacts.CONTENT_URI,
                new String[] { ContactsContract.Contacts.PHOTO_ID,
                        ContactsContract.Contacts.DISPLAY_NAME,
                        ContactsContract.Contacts._ID },
                ContactsContract.Contacts.HAS_PHONE_NUMBER, null,
                ContactsContract.Contacts.DISPLAY_NAME);
        cursor.moveToFirst();

        while (cursor.moveToNext()) {
            String currentName = cursor.getString(1);
            String currentId = cursor.getString(2);
            Cursor cursor2 = getContentResolver()
                    .query(android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            new String[] {
                                    ContactsContract.CommonDataKinds.Phone.NUMBER,
                                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME },
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID
                                    + " = ?",
                            new String[] { currentId }, null);
            while (cursor2.moveToNext()) {
                String currentNumber = cursor2.getString(0);
                if(isMobilePhone(currentNumber)) {
                    List<String> tmp = new ArrayList<String>();
                    tmp.add(currentName);
                    tmp.add(currentNumber);
                    out.add(tmp);
                    break;
                }
            }

        }
        return out;
    }

And I retrieve the array like this:

        List<List<String>> contacts = myServiceBinder.getContacts(txt);
        for(List<String> con : contacts) {
            String[] array = new String[con.size()];
            con.toArray(array); // fill the array
            Log.wtf("test",array[0]+" : "+array[1]);
        }

What am I doing wrong?


Solution

  • Your code is over complicated.

    1. As you can notice in your projection, you can access the contact ID and display-name directly from the Phones table
    2. You can iterate the Phones table directly, no need to query the Contacts table at all
    3. You can use SQLITE's LIKE operator to search your keyword in the DISPLAY_NAME field
    4. Instead of an Array of size 2, you can use Pair in your list

    Here's code:

    public List<Pair<String, String>> getContacts(String name) {
    
        List<Pair<String, String>> results = new ArrayList<>();
    
        String[] projection = new String[] { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER };
        String selection = Phone.DISPLAY_NAME + " LIKE '%" + name + "%'";
        Cursor cur = getContentResolver().query(Phone.CONTENT_URI, projection, selection, null, Phone.DISPLAY_NAME);
        while (cur.moveToNext()) {
            long contactId = cur.getLong(0);
            String name = cur.getString(1);
            String phone = cur.getString(2);
    
            Log.d("Contacts", "found: " + contactId + ", " + name + ", " + phone);
    
            results.add(Pair.create(name, phone));
        }
        cur.close();
    }