14

I am populating contact list details to list view successfully. My code:

  String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
  Cursor   curLog =  getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order); 

How can I avoid the duplicate data In List view as the contact details is repeating if its joined contact i.e. joined with both phone and Google?. The screen is like enter image description here

I want to select programmatically only 1 name not the both? Any Idea how I can select?

Kara
  • 6,115
  • 16
  • 50
  • 57
Subhalaxmi
  • 5,687
  • 3
  • 26
  • 42

8 Answers8

9

I have used a rough way to avoid this problem which helped me so much and working nicely.

i.e

Use local database (SQLite) to avoid duplicate data by make phone number to unique.

I have made one SQLite DB to handle this problem:

ContactMerger.java:

public class ContactMerger {

private static final String CONTACT_TABLE = "_contact_table";
private static final String CONTACT_ID = "_contactId";
private static final String CONTACT_NAME = "_contactName";
private static final String CONTACT_MOBILE_NUMBER = "_contactNumber";
private static final String CONTACT_DATE  = "_contactDate";


private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "DB_Contact";

private final Context context;
private SQLiteDatabase ourDatabase;
private DbHelper ourHelper;

private class DbHelper extends SQLiteOpenHelper {

    public DbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        String contactQuery = "CREATE TABLE " + CONTACT_TABLE + " ("
                + CONTACT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
                + CONTACT_NAME + " TEXT NOT NULL, " + CONTACT_DATE
                + " TEXT NOT NULL, " + CONTACT_MOBILE_NUMBER
                + " TEXT NOT NULL UNIQUE);";

        db.execSQL(contactQuery);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub
        db.execSQL("DROP TABLE IF EXISTS " + CONTACT_TABLE);
        onCreate(db);
    }

}

public ContactMerger(Context context) {
    this.context = context;
}

public ContactMerger open() throws SQLException {
    ourHelper = new DbHelper(context);
    ourDatabase = ourHelper.getWritableDatabase();
    return this;
}

public void close() {
    ourHelper.close();
}

// Insert Data to Contact Table
public long insertContacts(String name, String number, String date) throws SQLException {
    ContentValues cv = new ContentValues();
    cv.put(CONTACT_NAME, name);
    cv.put(CONTACT_DATE, date);
    cv.put(CONTACT_MOBILE_NUMBER, number);
    Log.d("Insert Data", cv.toString());
    return ourDatabase.insert(CONTACT_TABLE, null, cv);
}

//Get Contact details from Contact Table
public ArrayList<ContactHolder> getContactDetails() throws Exception{
    ArrayList<ContactHolder> contactDetails = new ArrayList<ContactHolder>();
    String[] columns = new String[] { CONTACT_ID, CONTACT_NAME, CONTACT_DATE, CONTACT_MOBILE_NUMBER };
    Cursor c = ourDatabase.query(CONTACT_TABLE, columns, null, null, null,null, null);

    int iContactName = c.getColumnIndex(CONTACT_NAME);  
    int iContactDate = c.getColumnIndex(CONTACT_DATE);  
    int iContactMobileNumber = c.getColumnIndex(CONTACT_MOBILE_NUMBER);

    for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {

        ContactHolder data = new ContactHolder();
        data.setName(c.getString(iContactName));
        data.setDate(c.getString(iContactDate));
        data.setNumber(c.getString(iContactMobileNumber));

        contactDetails.add(data);
    }

    return contactDetails;
 }
}

Here ContactHolder is just a getter/setter class to handle contact entities.

First I inserted all Contact information once in my MainActivity by the help of a background thread. It prevents to insert the contact info multiple times.

Something like:

private ArrayList<ContactHolder> contactHolder;
private void setCallLogs(Cursor managedCursor) {
    contactHolder = new ArrayList<ContactHolder>();

    int _number = managedCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    int _name = managedCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
    int _id = managedCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);


    while (managedCursor.moveToNext()) {

        ContactHolder holder = new ContactHolder();
        holder.setNumber(managedCursor.getString(_number));
        holder.setName(managedCursor.getString(_name));
        holder.setDate(managedCursor.getString(_id));
        contactHolder.add(holder);
    }
    Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            for(int i=0; i<contactHolder.size(); i++){
                try{
                    ContactMerger merger = new ContactMerger(HomeActivity.this);
                    merger.open();
                    merger.insertContacts(contactHolder.get(i).getName(),
                            contactHolder.get(i).getNumber(),
                            contactHolder.get(i).getdate());
                    merger.close();

                } catch(Exception e){
                     e.printStackTrace();
                }
            }

        }
    });

    t.start();  

}

At last I gtt all contact information inside an Asynctask(doInbackground()) and put in adapter/listview in its onPostExecute() method in the class I want to show.

Here:

@Override
    protected ArrayList<ContactHolder> doInBackground(String... parameters) {
        ArrayList<ContactHolder> filterContacts = new ArrayList<ContactHolder>();
        ContactMerger merger = new ContactMerger(Aaja_Contact.this);
        merger.open();
        try {
            filterContacts = merger.getContactDetails();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        merger.close();

        return filterContacts;
    }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ranjit
  • 5,130
  • 3
  • 30
  • 66
2

I believe this may happen if the contact number is stored in two different ways/formats: for example in your case the number for Akshay may be saved as 982-0123456 and 9820123456

Did you try displaying the number along with the Name by including the Number as well in the list view?

1

You need to retrieve the data from the Cursor to HashSet (which don't allows duplicate itmes) and then pass the HashSet object to your ListView's Adapter

This is a dump solution but it will help you:

ListView listView;
Set<String> listItems;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    listView = (ListView) findViewById(R.id.listView);
    listItems = new HashSet<String>();

    String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
    Cursor curLog =  getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order); 

    if(curLog != null) {
        while(curLog.moveToNext()) {
            String str = curLog.getString(curLog.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY));
            listItems.add(str);
        }
    }

    String listString = listItems.toString();
    listString = listString.substring(1,listString.length()-1);
    String[] newList = listString.split(", ");

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, newList);
    listView.setAdapter(adapter);        
}

Good luck..

Youcam39
  • 102
  • 5
  • I know that it is not a good solution but it works perfectly :) – Youcam39 Aug 01 '14 at 00:33
  • @babay +1 for the idea..but it can't solve the problem when you use a class instead of string ..ex: ArrayList ..because you have to maintain both names and numbers here. Thanks for the approach :) – Ranjit Sep 24 '14 at 08:58
0

Since you're querying Phone.CONTENT_URI, I'm assuming you're looking for contacts with phone number.. then you can use ContactsContract.Contacts.CONTENT_URI

String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,
                ContactsContract.Contacts.HAS_PHONE_NUMBER + "=?", new String[] { "1" }, order);
ColdFire
  • 6,764
  • 6
  • 35
  • 51
  • I am not asking how to get contact with phone number coz already i am getting all the details i need. My question is how can i avoid the duplicate details ?? Same contact name repeating so i want to filter only one. Any Idea ? – Subhalaxmi Jul 29 '14 at 09:38
  • by querying the `Contacts.CONTENT_URI` you won't be receiving duplicates – ColdFire Jul 29 '14 at 09:39
  • 1
    hmm i already tried by using " ContactsContract.Contacts " and result is same ?? Problem is if contact is saved with phone , sim and google etc – Subhalaxmi Jul 29 '14 at 10:03
  • read the question or at least think of updating the answer at a later stage. This is nothing less than SPAM. – Giridhar Karnik Mar 31 '17 at 19:09
0

Its because the listview is showing both normal contacts as well as whatsapp( or like this) linked contacts. Best is to store all the contacts in a Database and then retrieve the contacts using "select distinct..." command of SQL.

0
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
    Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, order);
    String temp_name="";
    while (phones.moveToNext())
    {
        String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        if (name.equals(temp_name))
            continue;
        temp_name=name;
       //add name to your list or adapter here`enter code here` 
    }
    phones.close();
waqasanwaar
  • 23
  • 1
  • 5
0

When you loop through your contacts, here's something you can do in the looping statement while you add your next object to avoid creating a duplicate contact:

UserList object=new UserList(name,number);
        if(arrayList.size()==0)
        {
            arrayList.add(object);
        }
        if(arrayList.size()>0) {
            position = arrayList.size();
            if (!(arrayList.get(arrayList.position - 1).getName().equals(number) || 
                arrayList.get(position - 1).getNumber().equals(number)))
               {
                arrayList.add(object); }  
          }

Here, in my object of 'UserList' class, the name and number would repeat from the contact list, so this code just checks if the previous object has the same name or number before adding in the new one.

0

Old question but still relevant. I could not find suitable query to skip dupes with contentresolver but it's possible to compare all contacts for duplicates by phone number. With com.googlecode.libphonenumber library it's really simple. Method public MatchType isNumberMatch(CharSequence firstNumber, CharSequence secondNumber) compares number, coutry code, mask and return one of MatchType enum value.

Stanislav Bondar
  • 6,056
  • 2
  • 34
  • 46