前言
- 查询联系人第一个需要先了解联系人的几个表关系和表字段不清楚的可以参照Android Developer关于联系人提供者(可能要翻墙)官方文档介绍或者参考 Android联系人模块分析(二) 做参考,不做过多介绍。
- 需要查询联系人数据网上大部分都是说
1. 查询ContactsContract.Contacts原始联系人列表
2. 通过原始联系人列表拿到的联系人id或者raw_contact_id查询ContactsContract.Data
联系人数据表获取到原始联系人详细信息(例如电子邮件地址或电话号码)
大致代码如下
/**
* 查询联系人数据
* @param context Context
* @return JSONArray
*/
fun queryContactData(context: Context): JSONArray {
val jsonArray = JSONArray()
val cursorContacts = context.contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
arrayOf(ContactsContract.Contacts._ID),
null,
null,
null
)
cursorContacts?.run {
while (moveToNext()) {
val id =
cursorContacts.getStringOrNull(getColumnIndex(ContactsContract.Contacts._ID))
val cursorData = context.contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID + " = ?",
arrayOf(id),
null
)
cursorData?.run {
//联系人名字
val name = JSONObject()
//联系人下的电话
val phoneArray = JSONArray()
while (moveToNext()) {
when (cursorData.getStringOrNull(getColumnIndex(ContactsContract.Data.MIMETYPE))) {
//添加名字
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
name.apply {
put(
"display_name",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME
)
)
)
put(
"given_name",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
)
)
)
put(
"family_name",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME
)
)
)
put(
"prefix",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.PREFIX
)
)
)
put(
"middle_name",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME
)
)
)
put(
"suffix",
cursorData.getStringOrNull(
getColumnIndex(
ContactsContract.CommonDataKinds.StructuredName.SUFFIX
)
)
)
}
}
//添加电话
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
JSONObject().apply {
put(
"number",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
)
put(
"type",
cursorData.getIntOrNull(getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE))
)
phoneArray.put(this)
}
}
//TODO("获取联系人其他详情数据")
}
}
close()
}
}
close()
}
JSONObject().apply {
put("name", name)
put("phone", phoneArray)
jsonArray.put(this)
}
return jsonArray
}
- 可以看到由于会查询两个表必定会影响查询速度,本人测试查询1163个联系人耗时平均大约在30秒左右
正文
- 由上面可以看出查询耗时主要在联表查询,其实我们需要的只是联系人详情数据故而可以换一种查询方式只查询ContactsContract.Data表
/**
* 查询联系人数据
* @param context Context
*/
fun queryContactData(context: Context) {
val cursorData = context.contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
null,
null,
null
)
cursorData?.run {
while (moveToNext()) {
cursorData
TODO("获取联系人详情数据")
}
close()
}
}
这样就会单独只查询ContactsContract.Data表,但是当你这样查询会发现一个问题出现了很多同一个联系人的数据,如果你有查看官方文档的联系人表关系就会发现ContactsContract.Data表对应的是联系人表的信息行,也就是比如一个手机号对应就是一个ContactsContract.Data表,所以会出现很多需要整理的信息
接下来就是需要整理获取到的联系人ContactsContract.Data表信息,我们需要把信息添加到同一个联系人中
1. 可以给contentResolver.query()查询语句添加排序让查询结果按raw_contact_id升序排序
2. 在游标cursorData返回中获取联系人的raw_contact_id 记录下来
3. 判断记录下来的raw_contact_id和上一次的raw_contact_id是否一样,一样说明是同一个联系人数据将数据添加到联系人数据对象中,不相同则创建一个新的联系人数据对象并将从游标cursorData获取到的联系人数据加入当然为了加快查询速度可以为contentResolver.query()查询语句添加查询指定数据这样会减少查询时间
以下是完整代码
private var name: JSONObject? = null
private var phoneArray: JSONArray? = null
/**
* 查询联系人数据
* @param context Context
*/
fun queryContactData(context: Context): JSONArray {
val jsonArray = JSONArray()
//记录raw_contact_id
var rawContactIdOld = ""
val cursorData = context.contentResolver.query(
ContactsContract.Data.CONTENT_URI,
arrayOf(
ContactsContract.Data.RAW_CONTACT_ID,
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.DATA1,
ContactsContract.Data.DATA2,
ContactsContract.Data.DATA3,
ContactsContract.Data.DATA4,
ContactsContract.Data.DATA5,
ContactsContract.Data.DATA6,
ContactsContract.CommonDataKinds.Photo.PHOTO
),
null,
null,
"${ContactsContract.Data.RAW_CONTACT_ID} ASC"//按raw_contact_id升序排序
)
cursorData?.run {
while (moveToNext()) {
//获取当前的联系人raw_contact_id
val rawContactId =
cursorData.getStringOrNull(getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID))
?: ""
if (rawContactId != rawContactIdOld) {//判断当前的和上一次的raw_contact_id是否一样,不一样说明不是同一个联系人数据
if (rawContactIdOld.isNotEmpty()) {
//添加联系人到数据中
addContactJSONArray(jsonArray)
}
name = JSONObject()
phoneArray = JSONArray()
rawContactIdOld = rawContactId
}
when (cursorData.getStringOrNull(getColumnIndex(ContactsContract.Data.MIMETYPE))) {
//添加名字
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
tryCatch {
name?.apply {
put(
"display_name",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
)
put(
"given_name",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME))
)
put(
"family_name",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME))
)
put(
"prefix",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PREFIX))
)
put(
"middle_name",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME))
)
put(
"suffix",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.SUFFIX))
)
}
}
}
//添加电话号码
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
tryCatch {
JSONObject().apply {
put(
"number",
cursorData.getStringOrNull(getColumnIndex(ContactsContract.Data.DATA1))
)
put(
"type",
cursorData.getIntOrNull(getColumnIndex(ContactsContract.Data.DATA2))
)
phoneArray?.put(this)
}
}
}
}
if (cursorData.isLast) {
//添加联系人到数据中
addContactJSONArray(jsonArray)
}
}
close()
}
return jsonArray
}
/**
* 添加联系人到数据中
* @param jsonArray JSONArray
*/
private fun addContactJSONArray(jsonArray: JSONArray) {
JSONObject().apply {
put("name", name)
put("phone", phoneArray)
jsonArray.put(this)
}
}
- 最终自己测试查询1163个联系人耗时平均大约在750毫秒左右