Мне кажется, что отмеченная проблема с производительностью связана с внутренней проблемой "n + 1 select" в предложенных реализациях.
- открыть курсор для перебора всех контактов (1)
- для каждого контакта откройте курсор, чтобы перебрать номера телефонов для этого контакта (n)
Более быстрый подход, если вам действительно нужны все эти данные, - это выполнить два запроса по контактам и телефонным номерам, вернув соответствующие суррогатные и первичные ключи, а затем выполнить объединение в памяти.
Запрос 1: получить все контакты в виде карты по ContactId
With the myriad of solutions proposed being sure to pull out the _ID field as the ContactId
Запрос 2: получить все номера телефонов и сохранить их в списке
Cursor c = MyO2Application.getContext().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER },
null,
null,
null
);
while (c.moveToNext()) {
String id = c.getString(0);
String contactId = c.getString(1); // this is the foreign key to the contact primary key
String displayName = c.getString(2);
String number = c.getString(3);
Затем можно выполнить итерацию по списку телефонных номеров, найти контакт на карте по ContactId и сопоставить номера телефонов с контактом.
Скорость выполнения 1000 контактов увеличена с 60 до 4 секунд. Как это часто бывает, существует компромисс между потреблением памяти и влиянием на GC.
Наблюдение при публикации: получение идентификаторов в виде int и использование SparseArray может оказаться подходящим подходом. Однако ожидается минимальное влияние по сравнению с проблемой «n + 1 select», рассматриваемой здесь.