Получение детальных сведений контакта

Этот урок показывает, как извлечь подробные данные для контакта, такие как адреса электронной почты, номера телефонов, и так далее. Это детали, которые пользователи ищут, когда они получают контакт. Вы можете дать им все подробные данные для контакта или только отобразить данные определенного типа, например, адреса электронной почты.

Шаги в этом уроке предполагают, что у вас уже есть ContactsContract.Contacts строка контакта, который выбрал пользователь. Получение списка имен контактов показывает, как получить список контактов.

Получение полной информации о контакте

Чтобы получить подробные данные контакта, выполните поиск по ContactsContract.Data таблице в поисках строк, содержащих LOOKUP_KEY. Эта колонка доступна в ContactsContract.Data таблице, потому что поставщик контактов делает неявное соединение между ContactsContract.Contacts таблицей и ContactsContract.Data таблицей. LOOKUP_KEY колонка более подробно описана в Получение списка имен контактов уроке.

Примечание: Получение всех полей для контакта снижает производительность устройства, потому что оно должно получить все столбцы из ContactsContract.Data таблицы. Рассмотрим влияние на производительность, прежде чем использовать данный метод.

Запрос разрешений

Для чтения из поставщика контактов, ваше приложение должно иметь READ_CONTACTS разрешение. Чтобы запросить это разрешение, добавьте следующий дочерний элемент в <manifest> в ваш файл манифеста:

    <uses-permission android:name="android.permission.READ_CONTACTS" />

Настройка проекции

В зависимости от типа данных, которые содержит строка, она может использовать как несколько столбцов так и много столбцов. Кроме того, данные находящиеся в разных столбцах зависят от типа данных. Чтобы получить все возможные столбцы для всех возможных типов данных, необходимо добавить имена всех столбцов в вашу проекцию. Всегда запрашивайте Data._ID если вы связываете результат Cursor c ListView; в противном случае, связывание не будет работать. Также получайте Data.MIMETYPE и вы сможете определить тип данных каждой извлеченной строки. Например:

    private static final String PROJECTION =
            {
                Data._ID,
                Data.MIMETYPE,
                Data.DATA1,
                Data.DATA2,
                Data.DATA3,
                Data.DATA4,
                Data.DATA5,
                Data.DATA6,
                Data.DATA7,
                Data.DATA8,
                Data.DATA9,
                Data.DATA10,
                Data.DATA11,
                Data.DATA12,
                Data.DATA13,
                Data.DATA14,
                Data.DATA15
            };

Эта проекция извлекает все подряд столбцы из ContactsContract.Data таблицы, используя имена столбцов, определенных в ContactsContract.Data класс.

Вы можете также использовать любые другие константы столбцов, определенные в или унаследованные от ContactsContract.Data класса. Заметим, однако, что столбцы от SYNC1 до SYNC4 предназначены для использования адаптерами синхронизации, так что их данные не нужны.

Определение критериев выбора

Определите константу для вашего запроса, массив для хранения аргументов выбора, и переменную для хранения значения выбора. Используйте Contacts.LOOKUP_KEY столбец для поиска контактов. Например:

    // Defines the selection clause
    private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
    // Defines the array to hold the search criteria
    private String[] mSelectionArgs = { "" };
    /*
     * Defines a variable to contain the selection value. Once you
     * have the Cursor from the Contacts table, and you've selected
     * the desired row, move the row's LOOKUP_KEY value into this
     * variable.
     */
    private String mLookupKey;

Использование "?" в качестве заполнителя в тексте вашего запроса гарантирует, что результат поиска формируется путем связывания, а не компиляции SQL. Такой подход исключает возможность вредоносных SQL инъекций.

Определение порядка сортировки

Определите желаемый порядок сортировки для результирующего Cursor. Чтобы держать все строки для конкретного типа данных вместе, отсортируйте по Data.MIMETYPE. Этот запрос группирует все строки электронной почты вместе, все строки телефонных номеров вместе, и так далее. Например:

    /*
     * Defines a string that specifies a sort order of MIME type
     */
    private static final String SORT_ORDER = Data.MIMETYPE;

Примечание: Некоторые типы данных не используют подтипы, поэтому вы не можете сортировать по подтипам. Вместо этого, вы должны пройтись по записям возвращенного Cursor, определите тип данных текущей строки, и сохранить данные для строк, которые имеют требуемый подтип. Когда вы закончите чтение курсора, вы можете отсортировать каждый тип данных по подтипам и отобразить результаты.

Инициализация загрузчика

Всегда выполняйте извлечение данных из поставщика контактов (и всех других поставщиков контента) в фоновом потоке. Используйте Loader, определенный в LoaderManager классе и LoaderManager.LoaderCallbacks интерфейс для выполнение извлечения данных в фоновом потоке.

Когда вы будете готовы к получению строк, инициализируйте загрузчик, вызвав initLoader(). Передайте целочисленный идентификатор методу; этот идентификатор передается в LoaderManager.LoaderCallbacks методы. Идентификатор позволяет использовать несколько загрузчиков в приложении, позволяя различать их.

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

public class DetailsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    // Defines a constant that identifies the loader
    DETAILS_QUERY_ID = 0;
    ...
    /*
     * Invoked when the parent Activity is instantiated
     * and the Fragment's UI is ready. Put final initialization
     * steps here.
     */
    @Override
    onActivityCreated(Bundle savedInstanceState) {
        ...
        // Initializes the loader framework
        getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);

Реализация onCreateLoader()

Реализуйте onCreateLoader() метод, который вызывается платформой загрузчика сразу после вызова initLoader(). Верните CursorLoader из этого метода. Так как вы ищете по ContactsContract.Data таблице, используйте константу Data.CONTENT_URI в качестве URI контента. Например:

    @Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        // Choose the proper action
        switch (loaderId) {
            case DETAILS_QUERY_ID:
            // Assigns the selection parameter
            mSelectionArgs[0] = mLookupKey;
            // Starts the query
            CursorLoader mLoader =
                    new CursorLoader(
                            getActivity(),
                            Data.CONTENT_URI,
                            PROJECTION,
                            SELECTION,
                            mSelectionArgs,
                            SORT_ORDER
                    );
            ...
    }

Реализация onLoadFinished() и onLoaderReset()

Реализуйте onLoadFinished() метод. Платформа загрузки вызывает onLoadFinished() когда поставщик контактов возвращает результаты запроса. Например:

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                    /*
                     * Process the resulting Cursor here.
                     */
                }
                break;
            ...
        }
    }

Метод onLoaderReset() вызывается, когда загрузчик обнаруживает, что данные результирующего Cursor изменились. В этот момент, удалите все существующие ссылки на Cursor , установив их в null. Если этого не сделать, платформа загрузки не сможет разрушить старый Cursor, и вы получите утечку памяти. Например:

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
                }
                break;
    }

Получение конкретных полей контакта

Для получения определенных типов данных для контакта, например, всех адресов электронной почты, следуйте той же схеме, что и для получения всех полей. Единственные изменения, которые необходимо внести в код, описаный в Получение полной информации о контакте:

Проекция
Измените вашу проекцию для получения столбцов, которые имеют специфичный тип данных. Также измените проекцию и используйте константы с именами столбцов, определенные в ContactsContract.CommonDataKinds подклассе, соответствующего типа данных.
Выделение
Изменить текст выбора для поиска MIMETYPE значение специфичное для вашего типа данных.
Порядок сортировки
Так как вы выбираете только один тип, не группируйте возвращаемый Cursor по Data.MIMETYPE.

Эти изменения описаны в следующих разделах.

Определение проекции

Определите столбцы, которые вы хотите получить, используя константы имен столбцов в подклассе ContactsContract.CommonDataKinds для этого типа данных. Если вы планируете связать ваш Cursor c ListView, убедитесь в получении _ID столбца. Например, для получения адресов электронной почты, определите следующую проекцию:

    private static final String[] PROJECTION =
            {
                Email._ID,
                Email.ADDRESS,
                Email.TYPE,
                Email.LABEL
            };

Обратите внимание, что эта проекция использует имена столбцов, определенные в классе ContactsContract.CommonDataKinds.Email, вместо имен столбцов, определенных в классе ContactsContract.Data. Использование имен столбцов специфичных для электронной почты делает код более удобным для чтения.

В проекции, вы также можете использовать любые другие столбцы, определенные в ContactsContract.CommonDataKinds подклассе.

Определение критериев выбора

Определите выражение поиска, которое извлекает строки конкретного контакта для LOOKUP_KEY и Data.MIMETYPE желаемых детальных данных. Заключите MIMETYPE значение в одинарные кавычки путем объединения "'"(одинарные кавычки) до и после константы; иначе, поставщик будет интерпретировать константу как имя переменной, а не как значение строки. Вам не нужно использовать заполнитель для этого значения, потому что вы используете константу, а не значение вводимое пользователем. Например:

    /*
     * Defines the selection clause. Search for a lookup key
     * and the Email MIME type
     */
    private static final String SELECTION =
            Data.LOOKUP_KEY + " = ?" +
            " AND " +
            Data.MIMETYPE + " = " +
            "'" + Email.CONTENT_ITEM_TYPE + "'";
    // Defines the array to hold the search criteria
    private String[] mSelectionArgs = { "" };

Определение порядка сортировки

Определите порядок сортировки для возвращаемого Cursor. Так как вы запрашиваете определенный тип данных, опустите сортировку по MIMETYPE. Вместо этого, если тип данных, которые вы ищете содержится в подтипе, сортируйте по нему. Например, для данных адресов электронной почты сортируйте по Email.TYPE:

    private static final String SORT_ORDER = Email.TYPE + " ASC ";