Оптимизация запроса contentProvider для получения имен контактов и телефонов - PullRequest
2 голосов
/ 22 сентября 2011

В настоящее время я использую этот код для получения имени контакта и номера телефона:

    ContentResolver contentResolver = getContentResolver();

    Cursor people = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

    int nameIndex = people.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
    int idIndex = people.getColumnIndex(ContactsContract.Contacts._ID);
    int hasPhoneNumberIndex = people.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);

    String name, id;
    int hasPhoneNumber;

    while(people.moveToNext()){
        name = people.getString(nameIndex);
        id = people.getString(idIndex);
        hasPhoneNumber = people.getInt(hasPhoneNumberIndex);

        if(hasPhoneNumber > 0){
            Cursor phones = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+id, null, null);
            phones.moveToFirst();

            int phoneIndex = phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            String phone = phones.getString(phoneIndex);

            HashMap<String, String> namePhoneType = new HashMap<String, String>();
            namePhoneType.put("Name", name);
            namePhoneType.put("Phone", phone);

            m_peopleList.add(namePhoneType);

            phones.close();
        }
    }

Но это очень медленно.

Есть ли способ получить имя и телефон только в одном запросе?

Ответы [ 3 ]

3 голосов
/ 05 сентября 2014

Мне кажется, что отмеченная проблема с производительностью связана с внутренней проблемой "n + 1 select" в предложенных реализациях.

  1. открыть курсор для перебора всех контактов (1)
  2. для каждого контакта откройте курсор, чтобы перебрать номера телефонов для этого контакта (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», рассматриваемой здесь.

0 голосов
/ 23 сентября 2011

Я нашел способ:

Cursor people = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER}, null, null,  Phone.DISPLAY_NAME + " ASC");
0 голосов
/ 23 сентября 2011

Подробнее о том, как это сделать, вы можете прочитать здесь

Вот фрагмент

//query for the people in your address book
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null,People.NAME + " ASC");
startManagingCursor(cursor);

//bind the name and the number fields
String[] columns = new String[] { People.NAME, People.NUMBER };
int[] to = new int[] { R.id.name_entry, R.id.number_entry };
SimpleContactAdapter mAdapter = new SimpleContactAdapter(this, R.layout.list_entry, cursor, columns, to);
this.setListAdapter(mAdapter);
...