• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

How Do I Get Rid Of Duplicate Numbers From The ContactsContract

ShatterStar

Newbie
I have a cursorLoader that return the phone numbers for the contacts on a user's phone, the problem is that I am getting back duplicate results. I am trying to get the unique results only. CursorLoader has a "selection" argument, how would I go about using this

Code:
return new CursorLoader(
        getContext(),
        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
        null,
        null,
        null,
          "DISPLAY_NAME ASC"
);
[/CODE
 
The "selection" parameter would contain the selection criteria. So let's suppose you had a table column called "_id", and you wish to retrieve all records where _id = 5.

The "selectionArgs" parameter contains a list of values which will be used to replace the selection values in your selection criteria string. So the following code -

Code:
String selection = "_id = ?";
String[] selectionArgs = new String[] { "5" };

return new CursorLoader(
        getContext(),
        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
        null,
        selection,
        selectionArgs,
          "DISPLAY_NAME ASC"
);

Will return all records where _id = 5

You can of course write a more complex selection criteria string, combining multiple columns, but you need to know a little bit about SQL statement syntax.
 
Hi LV426,

Good info but from what I read the "projection" parameter is the select statement, so id I want to do a "select distinct" how would I go about doing this? I have tried the code below but it doesn't work

Code:
private static final String[] myProjection = {
        "SELECT DISTINCT " + ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI,
        ContactsContract.CommonDataKinds.Phone.NUMBER
};
 
You're misunderstanding the role of the projection. It's to provide a destination for the various column values retrieved from the query. The query statement itself is specified by the "selection" parameter.
So your projection string above is incorrect.

See here for a good example of using a CursorLoader:

https://developer.android.com/guide/components/loaders.html

Code:
// These are the Contacts rows that we will retrieve.
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
        Contacts._ID,
        Contacts.DISPLAY_NAME,
        Contacts.CONTACT_STATUS,
        Contacts.CONTACT_PRESENCE,
        Contacts.PHOTO_ID,
        Contacts.LOOKUP_KEY,
    };
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created.  This
        // sample only has one Loader, so we don't care about the ID.
        // First, pick the base URI to use depending on whether we are
        // currently filtering.
        Uri baseUri;
        if (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                    Uri.encode(mCurFilter));
        } else {
            baseUri = Contacts.CONTENT_URI;
        }

        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        return new CursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION, select, null,
                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
    }
 
Hi Guys,

Huge frustration here, I have a custom cursorLoader and I am loading contacts from
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, however it is pulling through duplicate numbers once without any spaces and once with spaces. Now I have tried everything from a custom adapter to remove the duplicates but then my list item is empty and the convert views give me a problem while scrolling. I have tried a custom select string on the cursorloader but that doesn't work. Can someone please help me resolve this irritating issue
 
Duplicate threads merged.

Please post the code you're currently using.
 
This is in my fragment
Code:
private static final String[] From = {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Contacts.LOOKUP_KEY,

        ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI,
        ContactsContract.CommonDataKinds.Phone.NUMBER
};

private static final int[] To = new int[] {
        android.R.id.text1
};

CustomSimpleCursorAdapter mCursorAdapter;

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // Gets the ListView from the View list of the parent activity
    //mContactsList = (ListView) getActivity().findViewById(android.R.id.list);

    // Gets a CursorAdapter
    mCursorAdapter = new CustomSimpleCursorAdapter(
            getActivity(),
            R.layout.custom_contacts_list_item,
            null,
            From,
            To,
            0);

    // Sets the adapter for the ListView
    setListAdapter(mCursorAdapter);
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    String mySelection = "select " + ContactsContract.CommonDataKinds.Phone.NUMBER
            + " where " + ContactsContract.CommonDataKinds.Phone.TYPE
            + " = " + ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;


    /*
     * Makes search string into pattern and
     * stores it in the selection array
     */
    mSelectionArgs[0] = "%" + mSearchString + "%";
    // Starts the query
    return new CursorLoader(
            getContext(),
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            //ContactsContract.Contacts.CONTENT_URI,
            null,
            mySelection,
            null,
              "DISPLAY_NAME ASC"
    );
}

This is in my customAdapter
Code:
//ArrayList<String> phoneNumbersList = new ArrayList<String>();

@Override
public void bindView(View view, Context context, Cursor cursor) {
    super.bindView(view, context, cursor);

    ViewHolder viewHolder = (ViewHolder) view.getTag();

    /*String mPhoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replace(" ", "");

    for (int i = 0; i < phoneNumbersList.size(); i++) {
        if (phoneNumbersList.get(i).contains(mPhoneNumber) && i > 0) {
            return;
        }
    }

    phoneNumbersList.add(mPhoneNumber);*/



    int Title_index = cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
    viewHolder.displayName.setText(cursor.getString(Title_index));

    int phoneNumber = cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
    viewHolder.phoneNumber.setText(cursor.getString(phoneNumber));
}
 
I notice you had a "distinct" qualifier in your original query, which you don't have in the latest one. That would eliminate duplicates.
 
That didn't which is why I am posting here, do you notice the commented out for loop as well? I even tried that but then the list goes all wonky, any worthy suggestions?
 
The problem here is knowing what you're trying to do, and getting the right query to do the job. It would be useful to know the following:-

- The structure and content of the database table you're querying
- The exact database query that you're using

You can interactively query the database from the adb shell. I would suggest running your query on the database from here, and observe what rows are retrieved. Here's some information on how to do that:

https://www.simplifiedcoding.net/access-sqlite-database/
 
Here is a quick solution i came up with to remove duplicates

ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC ");

contactArray = new ArrayList<>();
String tempId = "";

if(cursor != null && cursor.getCount() > 0){
while(cursor.moveToNext())
{
String contact_id = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));

if(!tempId.equals(contact_id)){
String contact_name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String contact_number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String result = contact_id+"\n"+contact_name+"\n"+contact_number;
contactArray.add(result);
}

tempId = contact_id;

}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contactArray);
listView.setAdapter(adapter);
cursor.close();
 
Back
Top Bottom