【问题标题】:Getting contact information from contact list with Kotlin使用 Kotlin 从联系人列表中获取联系人信息
【发布时间】:2021-11-21 16:38:45
【问题描述】:

我正在尝试使用 Kotlin 获取有关用户可以在联系人列表中选择的联系人的一些信息。我尝试了一些仅部分有效的教程。这是应该从MainActivity.kt调用startActivityForResult()的代码:

add_contact.setOnClickListener {
    val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
    startActivityForResult(intent, CONTACT_PICK_CODE)
}

以下是被覆盖的onActivityResult方法:

@SuppressLint("Range")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    // handle intent results || calls when user from Intent (Contact Pick) picks or cancels pick contact
    if (resultCode == RESULT_OK) {
        if (requestCode == CONTACT_PICK_CODE) {
            val cursor1: Cursor
            val cursor2: Cursor?

            // get data from intent
            val uri = data!!.data
            cursor1 = contentResolver.query(uri!!, null, null, null, null)!!
            if (cursor1.moveToFirst()) {
                // get contact details
                val contactId = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID))
                val contactName = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
                val contactThumbnail = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))
                val idResults = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))
                val idResultHold = idResults.toInt()
                // check if contact has a phone number or not
                if (idResultHold == 1) {
                    cursor2 = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI,
                    null,
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId,
                    null,
                    null
                    )
                    // a contact may have multiple phone numbers
                    var contactNumber : String = ""
                    while (cursor2!!.moveToNext()) {
                        // get phone number
                        contactNumber = cursor2.getString(cursor2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                    }
                    Toast.makeText(this, "Contact number: $contactNumber", Toast.LENGTH_SHORT).show()
                    cursor2.close()
                }
                cursor1.close()
            }
        }
    } else {
        Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show()
    }
}

打印“Contact number: ...”的行从不打印联系电话,这意味着while 循环永远不会运行。

所有其他变量(contactIdcontactName...)似乎每次都被分配了正确的值,但数字却没有。有谁知道是什么原因造成的?

【问题讨论】:

    标签: java android xml kotlin


    【解决方案1】:
    cursor2 = > contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, ...
    

    要返回电话号码,您需要将 ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI Uri 替换为 ContactsContract.CommonDataKinds.Phone.CONTENT_URI

    您可以使用Set 来代替字符串,而不是使用重复的数字,因为;此 URI 返回电话存储以外的所有电话号码链接;比如谷歌、WhatsApp、..等。

    @SuppressLint("Range")
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
    
        // handle intent results || calls when user from Intent (Contact Pick) picks or cancels pick contact
        if (resultCode == RESULT_OK) {
            if (requestCode == CONTACT_PICK_CODE) {
                val cursor1: Cursor
                val cursor2: Cursor?
    
                // get data from intent
                val uri = data!!.data
                cursor1 = contentResolver.query(uri!!, null, null, null, null)!!
    
                if (cursor1.moveToFirst()) {
                    // get contact details
                    val contactId =
                        cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID))
                    val contactName =
                        cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
                    val contactThumbnail =
                        cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))
                    val idResults =
                        cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))
                    val idResultHold = idResults.toInt()
                    // check if contact has a phone number or not
                    if (idResultHold == 1) {
                        cursor2 = contentResolver.query(
    //                            ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, // WRONG
                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null,
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId,
                            null,
                            null
                        )
    
                        // a contact may have multiple phone numbers
                        val numbers = mutableSetOf<String>()
                        cursor2?.let {
                            while (cursor2.moveToNext()) {
                                val phoneNumber =
                                    cursor2.getString(
                                        cursor2.getColumnIndex(
                                            ContactsContract.CommonDataKinds.Phone.NUMBER
                                        )
                                    ).replace("-", "").replace(
                                        " ",
                                        ""
                                    )  // Remove the dash sign & spaces from the numbers
    
                                numbers.add(phoneNumber)
                            }
                            Toast.makeText(
                                this@MainActivity,
                                "$contactName $numbers",
                                Toast.LENGTH_LONG
                            ).show()
    
                            cursor2.close()
                        }
                        cursor1.close()
                    }
                }
    
    
            }
        } else {
            Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show()
        }
    }
    

    注意:您使用的是已弃用的 API onActivityResult,该 API 已替换为 registerForActivityResult

    这是一个使用它的演示:

    class MainActivity : AppCompatActivity() {
    
        private val requestSinglePermission =
            registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
                // Do something if permission granted
                if (isGranted) {
                    Log.d("LOG_TAG", "permission granted by the user")
    
                    // Do something as the permission is not granted
                } else {
                    Log.d("LOG_TAG", "permission denied by the user")
                }
            }
    
    
        private var allNumLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == Activity.RESULT_OK) {
                    // There are no request codes
                    val data = result.data?.data
    
                    data?.let {
                        val cursor = contentResolver.query(
                            data,
                            null,
                            null,
                            null,
                            null
                        )
    
                        cursor?.let {
                            if (it.moveToFirst()) {
                                val name =
                                    it.getString(it.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))
    
                                if (Integer.parseInt(
                                        it.getString(
                                            it.getColumnIndex(
                                                ContactsContract.Contacts.HAS_PHONE_NUMBER
                                            )
                                        )
                                    ) > 0 // Check if the contact has phone numbers
                                ) {
    
                                    val id =
                                        it.getString(it.getColumnIndex(ContactsContract.Contacts._ID))
    
                                    val phonesCursor = contentResolver.query(
                                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                        null,
                                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id,
                                        null,
                                        null
                                    )
    
                                    val numbers = mutableSetOf<String>()
                                    phonesCursor?.let {
                                        while (phonesCursor.moveToNext()) {
                                            val phoneNumber =
                                                phonesCursor.getString(
                                                    phonesCursor.getColumnIndex(
                                                        ContactsContract.CommonDataKinds.Phone.NUMBER
                                                    )
                                                ).replace("-", "").replace(" ", "")
                                            numbers.add(phoneNumber)
                                        }
                                        Toast.makeText(
                                            this@MainActivity,
                                            "$name $numbers",
                                            Toast.LENGTH_LONG
                                        ).show()
                                        Log.d(TAG, "$name $numbers")
                                    }
    
                                    phonesCursor?.close()
    
                                } else {
                                    Toast.makeText(
                                        this@MainActivity,
                                        "$name - No numbers",
                                        Toast.LENGTH_LONG
                                    ).show()
                                    Log.d(TAG, "$name - No numbers")
                                }
                            }
    
                            cursor.close()
                        }
    
                    }
                }
            }
    
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            if (ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.READ_CONTACTS
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                requestSinglePermission.launch(
                    Manifest.permission.READ_CONTACTS
                )
    
            }
    
    
            // get a contact:
            val intent = Intent(Intent.ACTION_PICK,
                    ContactsContract.Contacts.CONTENT_URI) 
            allNumLauncher.launch(intent)
    
        }
    }
    

    【讨论】:

    • 感谢您的详细解答!我尝试了您的代码,但由于某种原因,它仅在我打开应用程序后第一次选择联系人时才有效。之后的时间,它只显示一个空列表。为什么会这样?
    • @感谢您的评论。可能是此联系人没有关联的电话号码。我刚刚再次测试它,它可以多次使用。
    • 这很奇怪。也许这与我的Android版本有关?我有8.0。我看到实际上它很少起作用。也许它第一次工作只是一个巧合。对于某些联系人,它会返回正确的姓名和号码,而对于其他联系人(都有关联的电话号码)则不会。
    • 但是,我仍然设法使代码工作,方法是部分使用@Jabbar 的答案,然后添加获取联系人姓名的代码(并“清理”电话号码字符串)。我非常感谢添加的使用registerForActivityResult 的演示,我将尽我所能制作我现在使用的代码。我将分配 50 个代表。这个答案,因为它是最有用的。谢谢。
    • @EnricoCortinovis 我在 Android 11 上测试过,但让我在模拟器上的 Android 8 上检查一下
    【解决方案2】:

    试试这个从一个联系人那里获取多个电话号码

    const val REQUEST_SELECT_PHONE_NUMBER = 1
    
    fun selectContact() {
        // Start an activity for the user to pick a phone number from contacts
        val intent = Intent(Intent.ACTION_PICK).apply {
            type = CommonDataKinds.Phone.CONTENT_TYPE
        }
        if (intent.resolveActivity(packageManager) != null) {
            startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER)
        }
    }
    
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
        if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == Activity.RESULT_OK) {
            // Get the URI and query the content provider for the phone number
            val contactUri: Uri = data.data
            val projection: Array<String> = arrayOf(CommonDataKinds.Phone.NUMBER)
            contentResolver.query(contactUri, projection, null, null, null).use { cursor ->
                // If the cursor returned is valid, get the phone number
                if (cursor.moveToFirst()) {
                    val numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER)
                    val number = cursor.getString(numberIndex)
                    // Do something with the phone number
                    ...
                }
    
             val c: Cursor =  managedQuery(contactUri, null, null, null, null)
             val name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
    
            }
        }
    }
    

    【讨论】:

    • 谢谢!这行得通。我也在尝试获取联系人姓名(就像我的起始代码一样),val contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)) 就在您获得联系人号码的代码行之后,但它似乎不起作用。在 Logcat 中,它说错误出现在该行,并说 确保在从中访问数据之前正确初始化光标。你能解释为什么这不起作用吗?
    • 我认为你需要新的光标,(我已经更新了上面的代码。也看看这个answer
    • 我试过了,但它似乎不起作用。它给出了val name = ... 行的错误,说 Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size 1。每当应用程序到达那行代码时,它就会崩溃。我是否遗漏了什么,或者您知道是什么原因造成的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 2023-01-04
    • 2012-02-21
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多