使用 Kotlin 从联系人列表中获取联系人信息
Posted
技术标签:
【中文标题】使用 Kotlin 从联系人列表中获取联系人信息【英文标题】:Getting contact information from contact list with 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
循环永远不会运行。
所有其他变量(contactId
、contactName
...)似乎每次都被分配了正确的值,但数字却没有。有谁知道是什么原因造成的?
【问题讨论】:
【参考方案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。每当应用程序到达那行代码时,它就会崩溃。我是否遗漏了什么,或者您知道是什么原因造成的吗?以上是关于使用 Kotlin 从联系人列表中获取联系人信息的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Android 中的 Intent 中获取联系信息?
如何从 Android 中的联系人列表中获取联系人?使用联系提供商