You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:15:00