为啥 PhoneLookup 和 ContactsContract.Contacts 选择器之间的联系人 ID 不匹配?

Posted

技术标签:

【中文标题】为啥 PhoneLookup 和 ContactsContract.Contacts 选择器之间的联系人 ID 不匹配?【英文标题】:Why do contact IDs not match between PhoneLookup and the ContactsContract.Contacts picker?为什么 PhoneLookup 和 ContactsContract.Contacts 选择器之间的联系人 ID 不匹配? 【发布时间】:2018-12-03 08:23:49 【问题描述】:

我的应用正在扫描 SMS 消息并计算指标,然后将其存储在数据库中,该数据库由与 SMS 上的电话号码关联的联系人 ID 键入。使用PhoneLookup 机制查找第一个联系人ID。稍后,我还让用户使用联系人选择器意图选择联系人。但是即使选择了同一个人,从选择器返回的联系人 ID 与通过PhoneLookup 获取的联系人 ID 不同。这是为什么呢?

这是一个展示这种效果的活动。将PHONE_NUMBER 设置为您手机上已知联系人的电话号码。然后点击“选择联系人”按钮并选择相同的联系人。对我来说,这两种方法的联系人 ID 是不同的。

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.support.v7.app.AppCompatActivity
import android.util.Log
import com.example.R
import kotlinx.android.synthetic.main.activity_contact_idtest.*

class ContactIDTest : AppCompatActivity() 

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_contact_idtest)
    

    companion object 
        const val TAG = "ContactIDTest"
        const val RQST_PICK_CONTACT = 1
        const val PHONE_NUMBER = "5551234567"
    

    override fun onResume() 
        super.onResume()

        cmdPickContact.setOnClickListener 
            val pickContactIntent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
            pickContactIntent.type = ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE // Show user only contacts w/ phone numbers
            startActivityForResult(pickContactIntent, RQST_PICK_CONTACT)
        

        contactForPhoneNumber(PHONE_NUMBER,  contactID, displayName, photoThumbnailUri ->
            txtContactID.text = contactID.toString()
            txtContactName.text = displayName
        , 
            Log.e(TAG, "Error getting contact for phone number")
        )
    

    private fun contactForPhoneNumber(phoneNumber: String, callback: (contactID: Long, displayName: String?, photoThumbnailUri: String?) -> Unit, error: () -> Unit) 
        val contactURI = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber))

        try 
            val cursor = contentResolver.query(contactURI,
                    arrayOf(ContactsContract.PhoneLookup.CONTACT_ID, ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI),
                    null,
                    null,
                    null
            )

            if(cursor == null || cursor.count <= 0) 
                error()
             else 

                cursor.moveToFirst()

                val contactID = cursor.getLong(cursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup.CONTACT_ID))
                val displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup.DISPLAY_NAME))
                val photoThumbnailUri = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI))

                cursor.close()

                callback(contactID, displayName, photoThumbnailUri)

            

         catch(e: Exception) 
            Log.e(TAG, "Error loading contact for phone number: $phoneNumber", e)
        
    

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        if(requestCode == RQST_PICK_CONTACT) 
            if(resultCode == Activity.RESULT_OK) 

                val contactData = data!!.data
                val c = contentResolver.query(contactData, null, null, null, null)
                if(c.moveToFirst()) 
                    val contactID = c.getLong(c.getColumnIndex(ContactsContract.Contacts._ID))
                    val displayName = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))

                    txtPickedContactID.text = contactID.toString()
                    txtPickedContactName.text = displayName.toString()
                
                c.close()
            
        
    

还有布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutContactIDTest"
    android:layout_
    android:layout_
    tools:context=".activities.ContactIDTest"
    tools:layout_editor_absoluteY="81dp">

    <TextView
        android:id="@+id/txtContactName"
        android:layout_
        android:layout_
        android:text="$CONTACT_NAME"
        app:layout_constraintBottom_toTopOf="@+id/cmdPickContact"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtContactID" />

    <TextView
        android:id="@+id/txtContactID"
        android:layout_
        android:layout_
        android:text="$CONTACT_ID"
        app:layout_constraintBottom_toTopOf="@+id/txtContactName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/cmdPickContact"
        android:layout_
        android:layout_
        android:text="Pick Contact"
        app:layout_constraintBottom_toTopOf="@+id/txtPickedContactID"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtContactName" />

    <TextView
        android:id="@+id/txtPickedContactID"
        android:layout_
        android:layout_
        android:text="$PICKED_CONTACT_ID"
        app:layout_constraintBottom_toTopOf="@+id/txtPickedContactName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cmdPickContact" />

    <TextView
        android:id="@+id/txtPickedContactName"
        android:layout_
        android:layout_
        android:text="$PICKED_CONTACT_NAME"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txtPickedContactID" />
</android.support.constraint.ConstraintLayout>

【问题讨论】:

【参考方案1】:

这段代码:

val pickContactIntent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
pickContactIntent.type = ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE

将返回 CommonDataKinds.Phone._ID 而不是 Contacts._ID

【讨论】:

啊,这就是我无法 100% 理解的复制粘贴代码的结果。不知何故,我认为那是在做一些不同的事情。感谢您指出我的错误。

以上是关于为啥 PhoneLookup 和 ContactsContract.Contacts 选择器之间的联系人 ID 不匹配?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我需要 READ_CONTACTS 权限才能读取通话记录?

为啥 oracle 不支持在单个查询中更新多个表?

android中RawContacts.CONTENT_URI和ContactsContract.Contacts.CONTENT_URI的区别

Contacts解析

搜索和选择联系人

READ_CONTACTS 权限不起作用,除非我在 android SDK 23+ 上手动关闭和打开它