OBJECTIVE
I want to get for each contacts in the user phone the following data
StructuredName.GIVEN_NAME|Phone.NUMBER|Email.DATA|StructuredPostal.CITY
I'm pretty sure I query the ContactsContract.Data
table with a pure SQL query but the there is no clear documentation on how to do it.
It seems that you can inject SQL in the contentResolver.query but it does not seem to be sustainable.
PROBLEM
My code hereafter works perfectly but is very slow.
Basically,
- I get the IDs of ALL contacts from ContactsContract.Contacts and LOOP through it and for each,
- SELECT naming data on CommonDataKinds.StructuredName,
- SELECT and LOOP phone data on CommonDataKinds.Phone,
- SELECT and LOOP email data on CommonDataKinds.Email,
- SELECT and LOOP address data on CommonDataKinds.StructuredPostal
However, the many loops are obviously counterproductive in term of performance.
With a 1000 contacts, it makes around 3000 queries.
CODE
// CREATE Content resolver
val resolver: ContentResolver = contentResolver
val cursor = resolver.query(
ContactsContract.Contacts.CONTENT_URI,
arrayOf(
ContactsContract.Contacts._ID
),
null,
null,
null
)
if ( cursor != null && cursor.count > 0) {
// PROGRESSBAR Process
myProgressBar?.progress = 0
myProgressBarCircleText?.text = getString(R.string.processing_contacts)
myProgressBar?.visibility = View.VISIBLE
myProgressBarCircle?.visibility = View.VISIBLE
myProgressBarCircleText?.visibility = View.VISIBLE
// PUT BASIC REQUIRED INFO
val jsonAllContacts = JSONObject()
jsonAllContacts.put("source", "2")
// EXECUTE CODE on another thread to prevent blocking UI
Thread(Runnable {
var cursorPosition = 0
var currentProgress: Int
Log.e("JSON", "cursor.count: ${cursor.count}")
// CODE TO EXEC LOOP
while (cursor.moveToNext()) {
// Increment cursor for progressBar
cursorPosition += 1
currentProgress = ((cursorPosition.toFloat() / cursor.count.toFloat()) * 100).toInt()
// INIT of jsonObjects
val jsonEmail = JSONObject()
val jsonPhone = JSONObject()
val jsonAddress = JSONObject()
val jsonCurrentContact = JSONObject()
/**
* NAME DETAILS
*/
val contactID = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
val nameCur = contentResolver.query(
ContactsContract.Data.CONTENT_URI,
arrayOf(
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME
),
ContactsContract.Data.CONTACT_ID + " = ?" + " AND " + ContactsContract.Data.MIMETYPE + " = ?",
arrayOf(
contactID,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
),
null
)
var givenName = ""
var familyName: String
var middleName: String
var fullName = ""
if ( nameCur != null ) {
while (nameCur.moveToNext()) {
givenName = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)) ?: ""
middleName = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME)) ?: ""
familyName = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)) ?: ""
fullName = if ( middleName != "" && (middleName != familyName) ) {
"$middleName $familyName"
} else {
familyName
}
}
jsonCurrentContact.put("given", givenName)
jsonCurrentContact.put("family", fullName)
}
nameCur?.close()
/**
* PHONE NUMBER
*/
val phoneCur = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
arrayOf(
ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.LABEL,
ContactsContract.CommonDataKinds.Phone.NUMBER
),
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
arrayOf( contactID ),
null
)
if ( phoneCur != null && phoneCur.count > 0 ) {
while (phoneCur.moveToNext()) {
val phoneNumType = phoneCur.getString( phoneCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE) ) ?: ""
val phoneNumLabel = phoneCur.getString( phoneCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL) ) ?: ""
var label: String
val phoneNumber = phoneCur.getString( phoneCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) ).replace(" ", "") ?: ""
//Log.e("JSON", "JSON phoneNum: $phoneNumLabel $phoneNumber")
// TRY to get label info
label = if ( phoneNumType == "" ) {
phoneNumLabel
} else {
phoneNumType
}
jsonPhone.put("label", label)
jsonPhone.put("number", phoneNumber)
jsonCurrentContact.accumulate("phone", jsonPhone)
}
}
phoneCur?.close()
/**
* EMAIL
*/
val emailCur = contentResolver.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
arrayOf(
ContactsContract.CommonDataKinds.Email.LABEL,
ContactsContract.CommonDataKinds.Email.DATA
),
ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=?",
arrayOf(contactID),
null
)
if ( emailCur != null ) {
while (emailCur.moveToNext()) {
val emailLabel = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.LABEL)) ?: ""
val email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)) ?: ""
jsonEmail.put("label", emailLabel)
jsonEmail.put("email", email)
jsonCurrentContact.accumulate("email", jsonEmail)
}
}
emailCur?.close()
/**
* ADDRESS
*/
var street: String
var city: String
var postalCode: String
var state: String
var country: String
var label: String
val addressCur = contentResolver.query(
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI,
arrayOf(
ContactsContract.CommonDataKinds.StructuredPostal.TYPE,
ContactsContract.CommonDataKinds.StructuredPostal.STREET,
ContactsContract.CommonDataKinds.StructuredPostal.CITY,
ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE,
ContactsContract.CommonDataKinds.StructuredPostal.REGION,
ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY
),
ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID + "=" + contactID,
null,
null
)
if ( addressCur != null ) {
while (addressCur.moveToNext()) {
label = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)) ?: ""
street = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)) ?: ""
city = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)) ?: ""
postalCode = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)) ?: ""
state = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)) ?: ""
country = addressCur.getString(addressCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)) ?: ""
jsonAddress.put("label", label)
jsonAddress.put("street", street)
jsonAddress.put("city", city)
jsonAddress.put("postalcode", postalCode)
jsonAddress.put("state", state)
jsonAddress.put("country", country)
jsonCurrentContact.accumulate("address", jsonAddress)
}
}
addressCur?.close()
Log.e("", "jsonCurrentContact: $jsonCurrentContact")
// PUT the current JSON object info into an array
jsonAllContacts.accumulate("contacts", jsonCurrentContact)
}
cursor.close()
}).start()
} else {
cursor?.close()
}