Вот мой код Kotlin
, основанный на логике ответа @ marmor .
Этот оптимизированный код извлекает 1500 контактов в S7 Samsung за 500 мс вместо 3 минут.в коде вопроса .
Ради полноты я оставил фрагмент кода, который объединяет данные в объект JSON, и все детали для запуска процесса в отдельном потоке.
Thread(Runnable {
val resolver: ContentResolver = contentResolver
var jsonToSend = JSONObject()
var jsonAllContacts = JSONObject()
val jsonName = JSONObject()
val jsonEmail = JSONObject()
val jsonPhone = JSONObject()
val jsonAddress = JSONObject()
var cursorPosition = 0
var currentProgress: Int
val projection = arrayOf(
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.DATA1,
ContactsContract.Data.DATA2,
ContactsContract.Data.DATA3,
ContactsContract.Data.DATA4,
ContactsContract.Data.DATA5,
ContactsContract.Data.DATA6,
ContactsContract.Data.DATA7,
ContactsContract.Data.DATA8,
ContactsContract.Data.DATA9,
ContactsContract.Data.DATA10,
ContactsContract.Data.DATA11,
ContactsContract.Data.DATA12,
ContactsContract.Data.DATA13,
ContactsContract.Data.DATA14
)
val selection = ContactsContract.Data.MIMETYPE + " IN ('" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "', '" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "', '" + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE + "', '" + ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE + "')"
val order = "CASE WHEN " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "' THEN 0 ELSE 1 END ASC, '" + ContactsContract.Data.CONTACT_ID + "'"
val cursor = resolver.query(
ContactsContract.Data.CONTENT_URI,
projection,
selection,
null,
order
)
Log.e("cursor", "cursor STARTED")
if (cursor != null) {
while (cursor.moveToNext())
{
cursorPosition++
currentProgress = ((cursorPosition.toFloat() / cursor.count.toFloat()) * 100).toInt()
// SELECT the data needed from the standardized table
val id = cursor.getLong(0).toString()
val name = cursor.getString(1)
val mime = cursor.getString(2) // email / phone / postal
val data1 = cursor.getString(3) // the actual info, e.g. +1-212-555-1234
val data2 = cursor.getString(4)
val data3 = cursor.getString(5)
val data4 = cursor.getString(6)
val data5 = cursor.getString(7)
val data6 = cursor.getString(8)
val data7 = cursor.getString(9)
val data8 = cursor.getString(10)
val data9 = cursor.getString(11)
val data10 = cursor.getString(12)
val data11 = cursor.getString(13)
val data12 = cursor.getString(14)
val data13 = cursor.getString(15)
val data14 = cursor.getString(16)
// get the Contact class from the HashMap, or create a new one and add it to the Hash
when (mime) {
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
/**
* Type Alias Data column
* String DISPLAY_NAME DATA1
* String GIVEN_NAME DATA2
* String FAMILY_NAME DATA3
* String PREFIX DATA4 Common prefixes in English names are "Mr", "Ms", "Dr" etc.
* String MIDDLE_NAME DATA5
* String SUFFIX DATA6 Common suffixes in English names are "Sr", "Jr", "III" etc.
* String PHONETIC_GIVEN_NAME DATA7 Used for phonetic spelling of the name, e.g. Pinyin, Katakana, Hiragana
* String PHONETIC_MIDDLE_NAME DATA8
* String PHONETIC_FAMILY_NAME DATA9
*/
//Log.e("contact", "Name-- name:$name -- id:$id == 1:$data1 // 2:$data2 // 3:$data3 // 4: $data4 // 5:$data5 // 6:$data6 // 7:$data7 // 8:$data8 // 9:$data9 // 10:$data10 // 11:$data11 // 12:$data12 // 13:$data13 // 14:$data14")
val currentJSON = JSONObject()
val fullName = if ( data5 != null && (data5 != data3) ) {
"$data5 $data3"
} else {
data3 ?: data1 // PUT data1 as last resort because a contact with no names inputted will return something else (e.g. email address)
}
currentJSON.put("given", data2)
currentJSON.put("family", fullName)
jsonName.put( id, currentJSON)
}
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> {
/**
* IMPROVE - check that valueForJSON / data1 is a properly formatted email. It sometimes saves in the email the name of the person instead of the email.
* e.g. "aze qsd" instead of "aze.qsd@gmail.com"
*/
//Log.e("contact", "Email-- name:$name -- id:$id == 1:$data1 // 2:$data2 // 3:$data3 // 4: $data4 // 5:$data5 // 6:$data6 // 7:$data7 // 8:$data8 // 9:$data9 // 10:$data10 // 11:$data11 // 12:$data12 // 13:$data13 // 14:$data14")
val valueForJSON = data1
if ( jsonEmail.has(id) ) {
val indexString = jsonEmail[id].toString()
val indexArray = JSONObject(indexString)
if ( !indexArray.has(valueForJSON) ) {
jsonEmail.put( id, indexArray.put( valueForJSON, data2 ) )
}
} else {
jsonEmail.put( id, JSONObject().put( valueForJSON, data2 ) )
}
}
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
/**
* Type Alias Data column
String NUMBER ContactsContract.DataColumns.DATA1
int ContactsContract.CommonDataKinds.CommonColumns.TYPE ContactsContract.DataColumns.DATA2 Allowed values are:
ContactsContract.CommonDataKinds.BaseTypes.TYPE_CUSTOM. Put the actual type in ContactsContract.CommonDataKinds.CommonColumns.LABEL.
TYPE_HOME
TYPE_MOBILE
TYPE_WORK
etc..
String ContactsContract.CommonDataKinds.CommonColumns.LABEL ContactsContract.DataColumns.DATA3
String ContactsContract.CommonDataKinds.CommonColumns.NORMALIZED_NUMBER ContactsContract.DataColumns.DATA4
*/
//Log.e("contact", "Phone-- name:$name -- id:$id == 1:$data1 // 2:$data2 // 3:$data3 // 4: $data4 // 5:$data5 // 6:$data6 // 7:$data7 // 8:$data8 // 9:$data9 // 10:$data10 // 11:$data11 // 12:$data12 // 13:$data13 // 14:$data14")
val valueForJSON = data4 ?: data1
if ( jsonPhone.has(id) ) {
val indexString = jsonPhone[id].toString()
val indexArray = JSONObject(indexString)
if ( !indexArray.has(valueForJSON) ) {
jsonPhone.put( id, indexArray.put( valueForJSON, data2 ) )
}
} else {
jsonPhone.put( id, JSONObject().put( valueForJSON, data2 ) )
}
}
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE -> {
/**
* Type Alias Data column
String FORMATTED_ADDRESS ContactsContract.DataColumns.DATA1
int ContactsContract.CommonDataKinds.CommonColumns.TYPE ContactsContract.DataColumns.DATA2 Allowed values are:
ContactsContract.CommonDataKinds.BaseTypes.TYPE_CUSTOM. Put the actual type in ContactsContract.CommonDataKinds.CommonColumns.LABEL.
TYPE_HOME
TYPE_WORK
TYPE_OTHER
String ContactsContract.CommonDataKinds.CommonColumns.LABEL ContactsContract.DataColumns.DATA3
String STREET ContactsContract.DataColumns.DATA4
String POBOX ContactsContract.DataColumns.DATA5 Post Office Box number
String NEIGHBORHOOD ContactsContract.DataColumns.DATA6
String CITY ContactsContract.DataColumns.DATA7
String REGION ContactsContract.DataColumns.DATA8
String POSTCODE ContactsContract.DataColumns.DATA9
String COUNTRY ContactsContract.DataColumns.DATA10
*/
//Log.e("contact", "Address-- name:$name -- id:$id == 1:$data1 // 2:$data2 // 3:$data3 // 4: $data4 // 5:$data5 // 6:$data6 // 7:$data7 // 8:$data8 // 9:$data9 // 10:$data10 // 11:$data11 // 12:$data12 // 13:$data13 // 14:$data14")
val currentJSON = JSONObject()
val valueForJSON = data1
currentJSON.put("street", data4)
currentJSON.put("city", data7)
currentJSON.put("postcode", data9)
currentJSON.put("state", data8)
currentJSON.put("country", data10)
if ( jsonAddress.has(id) ) {
val indexString = jsonAddress[id].toString()
val indexArray = JSONObject(indexString)
if ( !indexArray.has(valueForJSON) ) {
jsonAddress.put( id, indexArray.put( valueForJSON, currentJSON ) )
}
} else {
jsonAddress.put( id, JSONObject().put( valueForJSON, currentJSON ) )
}
}
}
runOnUiThread {
//PROGRESS HERE
//myProgressBar?.visibility = View.VISIBLE
myProgressBar?.progress = currentProgress
}
}
}
cursor?.close()
// PUT some data to the first level of the nested JSON object
jsonToSend.put("source", "2")
/**
* ADD the type of contact info to the main jsonAllContacts Object
*/
jsonAllContacts = addNameToCurrentObject(jsonAllContacts, jsonName)
jsonAllContacts = addNewKeyToCurrentObject(jsonAllContacts, jsonPhone, "email")
jsonAllContacts = addNewKeyToCurrentObject(jsonAllContacts, jsonPhone, "phone")
jsonAllContacts = addNewKeyToCurrentObject(jsonAllContacts, jsonAddress, "address")
/**
* Remove the IDs that was used for aggregation of data
*/
jsonToSend = removeIDofObject(jsonToSend, jsonAllContacts)
}).start()