Android无法读取联系人地址求助:可获取姓名、电话与邮箱
问题分析与解决方案
你无法获取联系人地址的核心问题在于查询StructuredPostal时的条件错误,同时存在循环逻辑和查询安全性的问题,具体修正如下:
错误点说明
- 查询条件不匹配:你用
StructuredPostal.FORMATTED_ADDRESS + " = " + id作为关联条件,这是把联系人ID和地址内容做对比,完全逻辑错误,正确的关联字段应该是StructuredPostal.CONTACT_ID。 - 循环逻辑失效:遍历地址Cursor时用
while(postal.moveToFirst()),这只会执行一次(每次循环都会回到第一条数据),应该用moveToNext()遍历所有地址条目。 - 存在SQL注入风险:直接拼接ID到查询语句中不安全,建议使用参数化查询(
?占位符+参数数组)。
修正后的代码
val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickContact(), onResult = { uri -> uri ?: return@rememberLauncherForActivityResult val contentResolver: ContentResolver = ctx.contentResolver contentResolver.query(uri, null, null, null, null)?.use { cursor -> if (cursor.moveToFirst()) { changed = true val clientName = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) clientUiState.clientDetails.clientname = clientName Log.d("Name", clientName) val contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)) // 修正地址查询逻辑 contentResolver.query( StructuredPostal.CONTENT_URI, arrayOf(StructuredPostal.FORMATTED_ADDRESS), // 仅查询所需字段,提升性能 "${StructuredPostal.CONTACT_ID} = ?", arrayOf(contactId), null )?.use { postalCursor -> while (postalCursor.moveToNext()) { val address = postalCursor.getString(postalCursor.getColumnIndex(StructuredPostal.FORMATTED_ADDRESS)) clientUiState.clientDetails.clientAddress = address Log.d("Address", address) } } // 电话查询改为参数化写法,规避安全风险 contentResolver.query( Phone.CONTENT_URI, null, "${Phone.CONTACT_ID} = ?", arrayOf(contactId), null )?.use { phonesCursor -> while (phonesCursor.moveToNext()) { val phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(Phone.NUMBER)) clientUiState.clientDetails.clientPhone = phoneNumber Log.d("Number", phoneNumber) } } // 邮箱查询逻辑保持不变 contentResolver.query( Email.CONTENT_URI, null, "${Email.CONTACT_ID} = ?", arrayOf(contactId), null )?.use { emailCursor -> while (emailCursor.moveToNext()) { val email = emailCursor.getString(emailCursor.getColumnIndex(Email.DATA)) clientUiState.clientDetails.clientEmail = email Log.d("Email", email) } } } } } )
额外优化建议
- 使用
use函数自动管理Cursor生命周期,避免手动close遗漏导致的资源泄漏。 - 查询时明确指定需要的字段(而非传
null),减少内存占用和查询耗时。 - 一个联系人可能存在多个地址,当前代码会覆盖之前的地址值,若需保存所有地址,可改用集合类型存储。
内容的提问来源于stack exchange,提问作者RobTheChippy
相关产品推荐
相关产品推荐

