为什么联系人 ID 在 PhoneLookup 和 ContactsContract.Contacts 选择器之间不匹配?

Why do contact IDs not match between PhoneLookup and the ContactsContract.Contacts picker?

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

这里有一个 activity 显示了这种效果。将 PHONE_NUMBER 设置为您 phone 上已知联系人的 phone 号码。然后点击 "Pick Contact" 按钮和 select 相同的联系人。对我来说,这两种方法的联系人 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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activities.ContactIDTest"
    tools:layout_editor_absoluteY="81dp">

    <TextView
        android:id="@+id/txtContactName"
        android:layout_width="wrap_content"
        android:layout_height="21dp"
        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_width="wrap_content"
        android:layout_height="18dp"
        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_width="wrap_content"
        android:layout_height="wrap_content"
        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_width="wrap_content"
        android:layout_height="17dp"
        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_width="wrap_content"
        android:layout_height="wrap_content"
        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>

此代码:

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

return CommonDataKinds.Phone._ID 不是 Contacts._ID