Android获取联系人列表异常:代码正常运行但显示手机号而非邮箱
问题:Android联系人列表中邮箱字段显示为电话号码
首次尝试获取Android手机的联系人列表,代码可正常运行并填充列表,但存在问题:本该显示电子邮箱地址的地方却显示了电话号码,无法定位原因。
private fun getContacts() { arrayList.clear() val cursor = this.contentResolver .query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, arrayOf( ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Photo.PHOTO_URI, ContactsContract.CommonDataKinds.Email.ADDRESS, ),null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY ) while (cursor!!.moveToNext()) { val contactID = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)) val contactName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY)) val contactNumber = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)) val photo_uri = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.PHOTO_URI)) val contactEmail = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS)) val obj = ContactModel() obj.contid=contactID obj.contname = contactName obj.contnumber = contactNumber if (contactEmail != null) { obj.contemail=contactEmail } else { obj.contemail="No Email" } if(photo_uri != null){ obj.contPhoto = MediaStore.Images.Media.getBitmap(contentResolver,Uri.parse(photo_uri)) } arrayList.add(obj) } rcvAdapter.notifyDataSetChanged() cursor.close() }
问题原因
核心错误在于用ContactsContract.CommonDataKinds.Phone.CONTENT_URI(电话数据专属URI)去查询ContactsContract.CommonDataKinds.Email.ADDRESS(邮箱字段)。
Android联系人数据结构里,Phone.CONTENT_URI指向的是仅存储电话信息的数据表,这个表根本没有Email.ADDRESS对应的列。强行查询该字段时,getColumnIndexOrThrow会返回无效索引,大概率和Phone.NUMBER的索引重合,导致你拿到的还是电话号码,而非邮箱地址。
另外,一个联系人可能有多个电话或邮箱,直接用Phone的URI查询会生成多条重复的联系人记录(对应多个电话),同时完全无法获取邮箱数据。
解决方案
正确做法是通过ContactsContract.Data.CONTENT_URI统一查询所有联系人数据,或者先获取联系人基本信息,再根据CONTACT_ID单独查询邮箱。以下是优化后的统一查询代码,同时处理同一联系人多电话、多邮箱的情况:
private fun getContacts() { arrayList.clear() val contactMap = mutableMapOf<String, ContactModel>() // 统一查询联系人的电话、邮箱、姓名、头像信息 val cursor = contentResolver.query( ContactsContract.Data.CONTENT_URI, arrayOf( ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME_PRIMARY, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Photo.PHOTO_URI, ContactsContract.Data.MIMETYPE // 区分当前行是电话还是邮箱 ), "${ContactsContract.Data.MIMETYPE} IN (?, ?)", arrayOf( ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ), "${ContactsContract.Data.DISPLAY_NAME_PRIMARY} ASC" ) cursor?.use { // use函数自动关闭cursor,避免资源泄漏 while (it.moveToNext()) { val contactId = it.getString(it.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID)) val name = it.getString(it.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME_PRIMARY)) val photoUri = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Photo.PHOTO_URI)) val mimeType = it.getString(it.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE)) // 从map中获取或创建联系人模型,避免重复 val contactModel = contactMap.getOrPut(contactId) { ContactModel().apply { contid = contactId contname = name contnumber = "No Phone" contemail = "No Email" photoUri?.let { uri -> contPhoto = MediaStore.Images.Media.getBitmap(contentResolver, Uri.parse(uri)) } } } // 根据MIME类型区分电话和邮箱,更新对应字段 when (mimeType) { ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> { val number = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)) contactModel.contnumber = number } ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> { val email = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS)) contactModel.contemail = email ?: "No Email" } } } } // 将去重后的联系人转为列表 arrayList.addAll(contactMap.values) rcvAdapter.notifyDataSetChanged() }
代码说明:
- 使用
ContactsContract.Data.CONTENT_URI:这是所有联系人数据的统一入口,包含电话、邮箱、地址等各类信息。 - 通过
MIMETYPE过滤数据:只查询电话和邮箱类型的数据,避免无关数据干扰。 - 用
MutableMap去重:确保同一个联系人只创建一个ContactModel,合并其所有电话和邮箱信息(若需支持多电话/多邮箱,可修改ContactModel添加列表字段)。 - 使用
use函数自动关闭Cursor:简化资源管理,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

