在我的应用程序中,我想显示一个列表,其中包含我的联系人及其每个人的电话号码。因此,我从 ContentProvider 获取联系人,然后获取手机的所有号码,然后通过联系人 ID 进行匹配。代码如下
fun Context.retrieveAllContacts(): List<ContactData> {
val result: MutableList<ContactData> = mutableListOf()
contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
CONTACT_PROJECTION,
null,
null,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
)?.use {
if (it.moveToFirst()) {
do {
val contactId = it.getString(it.getColumnIndex(CONTACT_PROJECTION[0]))
val firstName = it.getString(it.getColumnIndex(CONTACT_PROJECTION[2])) ?: ""
val lastName = it.getString(it.getColumnIndex(CONTACT_PROJECTION[3])) ?: ""
val initials = getInitials(firstName, lastName)
result.add(ContactData(contactId, firstName, initials, mutableListOf(), null))
} while (it.moveToNext())
}
}
return result
}
fun Context.retrieveAllContactNumbers(): HashMap<String, ArrayList<String>> {
val contactsNumberMap = HashMap<String, ArrayList<String>>()
val phoneCursor: Cursor? = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
null
)
if (phoneCursor != null && phoneCursor.count > 0) {
val contactIdIndex =
phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
val numberIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
while (phoneCursor.moveToNext()) {
val contactId = phoneCursor.getString(contactIdIndex)
val number: String = phoneCursor.getString(numberIndex)
// check if the map contains key or not, if not then create a new array list with number
if (contactsNumberMap.containsKey(contactId)) {
contactsNumberMap[contactId]?.add(number)
} else {
contactsNumberMap[contactId] = arrayListOf(number)
}
}
// contact contains all the number of a particular contact
phoneCursor.close()
}
return contactsNumberMap
}
之后我运行一个循环来进行通信
val contactsListAsync = async { context?.retrieveAllContacts() ?: emptyList() }
val contacts = contactsListAsync.await()
val contactNumbersAsync = async { requireActivity().retrieveAllContactNumbers() }
val contactNumbers = contactNumbersAsync.await()
contacts.forEach { contactData ->
contactNumbers[contactData.contactId]?.let { numbers ->
numbers.forEach {
if (isValidIrisCellphoneNumber(PhoneNumberUtils.normalizeNumber(it)))
contactData.phoneNumbers.add(it)
}
}
}
正如我所看到的,许多联系人都有相同的号码 2 或 3 次或 evan 4 次。我猜“问题”来自
retrieveAllContactNumbers()
,它从 ContactsContract.CommonDataKinds.Phone
获取数字。大多数情况下,我想知道为什么会发生这种情况,然后如何防止它?
我还注意到了这一点:我添加了一个假联系人,并且在我的列表中看到它有 2 个号码。也许这与 contentResolver 从哪里获取数字有关?例如 Google 帐户、SIM 卡、内部存储...?我不知道...
联系人数据库的组织方式符合预期:
Contacts
- 每个条目代表一个联系人,并将一个或多个组合在一起 RawContacts
RawContacts
- 每个条目代表由某些 SyncAdapter
(例如 Whatsapp、Google、Facebook、Viber)同步的联系人数据,这对多个数据条目进行分组Data
- 有关联系人、电子邮件、电话等的实际数据。每一行都是属于单个 RawContact
您应该直接从
Data
表查询电话,因此您可能会从代表相同 RawContacts
的不同 Contact
获得相同的电话号码。
例如,如果您的设备上安装了 Whatsapp,并且 Google 正在同步您的联系人,则每个联系人可以并且将会存储相同的电话号码 2 个 RawContacts - 每个应用程序一个。
简单的解决方案是将您的地图更改为:
val contactsNumberMap = HashMap<String, Set<String>>()
Set
将强制每个联系人的电话列表具有唯一性。