Android - 删除重复的联系人
Android - Remove Duplicate Contacts
我正在尝试在 Recycler View 中显示联系人,一切正常,但联系人显示两次或三次。
这是代码
RecyclerView recyclerView;
List<Contacts> contactsList;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
if (contactsList.contains(contacts)){
cursor.moveToNext();
}
else {
contactsList.add(contacts);
}
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
那么,我该如何解决这个问题呢?
仅将 phoneNumber 作为键传递,将 phoneName 作为值传递
您可以使用:
Map<String, String> map = new HashMap<>();
map.put("A", "1");
...
System.out.printf("Before: %s%n", map);
// Set in which we keep the existing values
Set<String> existing = new HashSet<>();
map = map.entrySet()
.stream()
.filter(entry -> existing.add(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.printf("After: %s%n", map);
例如:
Before: {A=1, B=2, C=2, D=3, E=3} After: {A=1, B=2, D=3}
您可以按照此页面上的这些步骤操作,我可以在此处提供完整的解决方案 link
我认为您应该考虑几个问题。是查询错误还是我保存联系人的方式不对?
在您的应用中是否应该允许重复联系人?如果否,您可以在迁移中添加 unique constraint
。参见 Sql Lite Unique Constraints
如果您的数据库应该接受重复值,那么您应该添加一个列来表示该用户的唯一值?即 userId 列或联系人关联的位置,然后将其作为 Selection 和 SelectionArgs 添加到您的查询中。
最后,如果您只是想快速解决问题...您应该更深入地研究过滤。
您的代码 contactsList.contains(contacts)
永远不会正确,因为您总是在上面的行中创建联系人。然后您正在检查您的列表是否包含新创建的列表。否则你可以使用上面的解决方案
您可以覆盖 class 联系人中的 equals() 方法。这样,如果两个联系人对象在您的覆盖方法中逻辑上相等,则您的 contactList.contains(Contact c) 可以评估为真,因此它不会再次将其添加到列表中。
@Override
public boolean equals(Object o){
if(!o.getClass().equals(Contacts.class)) return false;
Contact c2 = (Contact)o;
// if phonenumber is unique to differentiate contact
return c2.number.equals(number);
}
您可以将 List 更改为 HashSet。 HashSet 防止 有重复项。你的最终代码应该是这样的:
RecyclerView recyclerView;
HashSet<Contacts> contactsSet;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
contactsSet.add(contacts);
}
List<Contacts> contactsList = new ArrayList<>();
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
我正在尝试在 Recycler View 中显示联系人,一切正常,但联系人显示两次或三次。
这是代码
RecyclerView recyclerView;
List<Contacts> contactsList;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
if (contactsList.contains(contacts)){
cursor.moveToNext();
}
else {
contactsList.add(contacts);
}
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
那么,我该如何解决这个问题呢?
仅将 phoneNumber 作为键传递,将 phoneName 作为值传递 您可以使用:
Map<String, String> map = new HashMap<>();
map.put("A", "1");
...
System.out.printf("Before: %s%n", map);
// Set in which we keep the existing values
Set<String> existing = new HashSet<>();
map = map.entrySet()
.stream()
.filter(entry -> existing.add(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.printf("After: %s%n", map);
例如:
Before: {A=1, B=2, C=2, D=3, E=3} After: {A=1, B=2, D=3}
您可以按照此页面上的这些步骤操作,我可以在此处提供完整的解决方案 link
我认为您应该考虑几个问题。是查询错误还是我保存联系人的方式不对?
在您的应用中是否应该允许重复联系人?如果否,您可以在迁移中添加 unique constraint
。参见 Sql Lite Unique Constraints
如果您的数据库应该接受重复值,那么您应该添加一个列来表示该用户的唯一值?即 userId 列或联系人关联的位置,然后将其作为 Selection 和 SelectionArgs 添加到您的查询中。
最后,如果您只是想快速解决问题...您应该更深入地研究过滤。
您的代码 contactsList.contains(contacts)
永远不会正确,因为您总是在上面的行中创建联系人。然后您正在检查您的列表是否包含新创建的列表。否则你可以使用上面的解决方案
您可以覆盖 class 联系人中的 equals() 方法。这样,如果两个联系人对象在您的覆盖方法中逻辑上相等,则您的 contactList.contains(Contact c) 可以评估为真,因此它不会再次将其添加到列表中。
@Override
public boolean equals(Object o){
if(!o.getClass().equals(Contacts.class)) return false;
Contact c2 = (Contact)o;
// if phonenumber is unique to differentiate contact
return c2.number.equals(number);
}
您可以将 List 更改为 HashSet。 HashSet 防止 有重复项。你的最终代码应该是这样的:
RecyclerView recyclerView;
HashSet<Contacts> contactsSet;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
contactsSet.add(contacts);
}
List<Contacts> contactsList = new ArrayList<>();
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}