В этом уроке рассказывается, как получить подробные данные о контакте, например адреса электронной почты, номера телефонов и т. д. Это сведения, которые пользователи ищут, когда находят контакт. Вы можете предоставить им все сведения о контакте или отобразить только сведения определенного типа, например адреса электронной почты.
Предполагается, что у вас уже есть строка 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 с ListView, иначе связывание не будет работать. Также получите Data.MIMETYPE, чтобы определить тип данных каждой строки. Пример:
Kotlin
private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Data._ID, 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, ContactsContract.Data.DATA15 )
Java
private static final String[] PROJECTION = { ContactsContract.Data._ID, 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, ContactsContract.Data.DATA15 };
Эта проекция извлекает все столбцы для строки в таблице ContactsContract.Data, используя названия столбцов, определенные в классе ContactsContract.Data.
Вы также можете использовать любые другие константы столбцов, определенные в классе ContactsContract.Data или унаследованные им. Однако обратите внимание, что столбцы с SYNC1 по SYNC4 предназначены для использования адаптерами синхронизации, поэтому их данные не представляют интереса.
Определите критерии отбора
Определите константу для условия выбора, массив для хранения аргументов выбора и переменную для хранения значения выбора. Чтобы найти контакт, используйте столбец Contacts.LOOKUP_KEY. Пример:
Kotlin
// Defines the selection clause private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("") /* * 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 var lookupKey: String? = null
Java
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" }; /* * 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 lateinit var lookupKey: String
Использование символа "?" в качестве плейсхолдера в текстовом выражении выбора гарантирует, что результирующий поиск будет сгенерирован путем привязки, а не компиляции SQL. Такой подход исключает возможность внедрения вредоносного SQL-кода.
Как задать порядок сортировки
Укажите порядок сортировки в результирующем массиве Cursor. Чтобы сгруппировать строки по типу данных, отсортируйте их по столбцу Data.MIMETYPE. Этот аргумент запроса группирует все строки с адресами электронной почты, все строки с номерами телефонов и т. д. Пример:
Kotlin
/* * Defines a string that specifies a sort order of MIME type */ private const val SORT_ORDER = ContactsContract.Data.MIMETYPE
Java
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;
Примечание. Некоторые типы данных не используют подтип, поэтому вы не можете сортировать по подтипу.
Вместо этого вам нужно перебрать возвращенные объекты Cursor, определить тип данных текущей строки и сохранить данные для строк, в которых используется подтип. Завершив чтение курсора, вы можете отсортировать каждый тип данных по подтипу и отобразить результаты.
Инициализация загрузчика
Всегда выполняйте извлечение данных из поставщика контактов (и всех других поставщиков контента) в фоновом потоке. Используйте фреймворк загрузчика, определенный классом LoaderManager и интерфейсом LoaderManager.LoaderCallbacks, для фонового получения данных.
Когда вы будете готовы получить строки, инициализируйте фреймворк загрузчика, вызвав initLoader(). Передайте методу целочисленный идентификатор, который затем будет передан методам LoaderManager.LoaderCallbacks. Идентификатор позволяет использовать в приложении несколько загрузчиков и различать их.
В следующем фрагменте кода показано, как инициализировать фреймворк загрузчика:
Kotlin
// Defines a constant that identifies the loader private const val DETAILS_QUERY_ID: Int = 0 class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Initializes the loader framework loaderManager.initLoader(DETAILS_QUERY_ID, null, this)
Java
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Defines a constant that identifies the loader static int DETAILS_QUERY_ID = 0; ... @Override public void onCreate(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
Как реализовать onCreateLoader()
Реализуйте метод onCreateLoader(), который вызывается фреймворком загрузчика сразу после вызова initLoader(). Этот метод должен возвращать CursorLoader. Поскольку вы выполняете поиск в таблице ContactsContract.Data, используйте константу Data.CONTENT_URI в качестве URI контента.
Пример:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { // Choose the proper action mLoader = when(loaderId) { DETAILS_QUERY_ID -> { // Assigns the selection parameter selectionArgs[0] = lookupKey // Starts the query activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } } ... } return mLoader }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter selectionArgs[0] = lookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ); }
Реализация onLoadFinished() и onLoaderReset()
Реализуйте метод onLoadFinished(). Фреймворк загрузчика вызывает
onLoadFinished()
когда поставщик контактов возвращает результаты запроса. Пример:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { when(loader.id) { DETAILS_QUERY_ID -> { /* * Process the resulting Cursor here. */ } ... } }
Java
@Override 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, что приведет к утечке памяти. Пример:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { when (loader.id) { DETAILS_QUERY_ID -> { /* * If you have current references to the Cursor, * remove them here. */ } ... } }
Java
@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 с ListView, обязательно получите столбец _ID. Например, чтобы получить данные электронной почты, определите следующую проекцию:
Kotlin
private val PROJECTION: Array<String> = arrayOf( ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL )
Java
private static final String[] PROJECTION = { ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL };
Обратите внимание, что в этой проекции используются названия столбцов, определенные в классе ContactsContract.CommonDataKinds.Email, а не в классе ContactsContract.Data. Использование названий столбцов, относящихся к электронной почте, делает код более читабельным.
В проекции также можно использовать любые другие столбцы, определенные в подклассе ContactsContract.CommonDataKinds.
Как задать критерии отбора
Определите текстовое выражение для поиска, которое извлекает строки для определенного контакта LOOKUP_KEY и Data.MIMETYPE нужных вам сведений. Заключите значение MIMETYPE в одинарные кавычки, добавив символ ' в начале и в конце константы. В противном случае поставщик будет интерпретировать константу как название переменной, а не как строковое значение. Вам не нужно использовать плейсхолдер для этого значения, поскольку вы используете константу, а не значение, предоставленное пользователем. Пример:
Kotlin
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private const val SELECTION = "${ContactsContract.Data.LOOKUP_KEY} = ? AND " + "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("")
Java
/* * 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[] selectionArgs = { "" };
Как задать порядок сортировки
Определите порядок сортировки для возвращенного Cursor. Поскольку вы извлекаете данные определенного типа, сортировку по MIMETYPE можно опустить.
Если у типа данных, которые вы ищете, есть подтип, отсортируйте данные по нему.
Например, для данных электронной почты можно выполнить сортировку по следующим полям Email.TYPE:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";