В этом уроке рассказывается, как получить список контактов, данные которых соответствуют строке поиска полностью или частично, используя следующие методы:
- Сопоставлять имена контактов
- Получить список контактов, сопоставив строку поиска со всем или частью имени контакта. Поставщик контактов допускает несколько экземпляров одного и того же имени, поэтому этот метод может возвращать список совпадений.
- Сопоставление с определенным типом данных, например номером телефона
- Получение списка контактов путем сопоставления строки поиска с определенным типом данных, например адресом электронной почты. Например, с помощью этого метода можно получить список всех контактов, адрес электронной почты которых соответствует строке поиска.
- Сопоставить любой тип данных
- Получить список контактов, соответствующих поисковому запросу, по любому типу данных, включая имя, номер телефона, почтовый адрес, адрес электронной почты и т. д. Например, этот метод позволяет принимать любые типы данных для строки поиска, а затем выводить список контактов, для которых данные соответствуют строке.
Примечание. Во всех примерах в этом уроке для получения данных от поставщика контактов используется CursorLoader. CursorLoader выполняет запрос в потоке, отдельном от потока UI. Это гарантирует, что запрос не замедлит работу интерфейса и не ухудшит удобство использования. Подробную информацию можно найти в статье
Загрузка данных в фоновом режиме.
Запросить разрешение на чтение данных поставщика
Чтобы выполнять поиск в поставщике контактов, у приложения должно быть разрешение READ_CONTACTS.
Чтобы запросить это разрешение, добавьте следующий элемент <uses-permission> в файл манифеста в качестве дочернего элемента <manifest>:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Найти контакт по имени и показать результаты
Этот метод пытается сопоставить строку поиска с именем контакта или контактов в таблице ContactsContract.Contacts поставщика контактов. Обычно результаты поиска выводятся в виде списка ListView, чтобы пользователь мог выбрать нужный контакт.
Как задать макеты ListView и элементов
Чтобы показать результаты поиска в ListView, вам нужен основной файл макета, который определяет весь интерфейс, включая ListView, и файл макета элемента, который определяет одну строку ListView. Например, вы можете создать основной файл макета res/layout/contacts_list_view.xml со следующим XML-кодом:
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
В этом XML-коде используется встроенный виджет Android ListView
android:id/list.
Определите файл макета элемента contacts_list_item.xml с помощью следующего XML-кода:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"/>
В этом XML-коде используется встроенный виджет Android TextView
android:text1.
Примечание. В этом уроке не описывается пользовательский интерфейс для получения строки поиска от пользователя, поскольку вы можете получить строку косвенно. Например, вы можете предоставить пользователю возможность искать контакты, имя которых совпадает со строкой во входящем текстовом сообщении.
Два файла макета, которые вы написали, определяют пользовательский интерфейс, в котором показывается ListView. Теперь нужно написать код, который будет использовать этот интерфейс для отображения списка контактов.
Определение фрагмента, отображающего список контактов
Чтобы показать список контактов, сначала определите Fragment, который загружается с помощью Activity. Использование Fragment – более гибкий метод, поскольку вы можете использовать один Fragment для отображения списка и второй Fragment для отображения сведений о контакте, который пользователь выбирает из списка. Таким образом, вы можете объединить один из методов, описанных в этом уроке, с одним из методов, описанных в уроке
Как получить информацию о контакте.
Чтобы узнать, как использовать один или несколько объектов Fragment из Activity, ознакомьтесь с учебным курсом
Создание динамического пользовательского интерфейса с помощью фрагментов.
Чтобы вам было проще писать запросы к поставщику контактов, в платформе Android есть класс контрактов ContactsContract, в котором определены полезные константы и методы для доступа к поставщику. При использовании этого класса вам не нужно определять собственные константы для URI контента, названий таблиц или столбцов. Чтобы использовать этот класс, добавьте следующее утверждение:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
Поскольку код использует CursorLoader для получения данных от поставщика, необходимо указать, что он реализует интерфейс загрузчика LoaderManager.LoaderCallbacks. Чтобы определить, какой контакт пользователь выбрал из списка результатов поиска, реализуйте интерфейс адаптера AdapterView.OnItemClickListener. Пример:
Kotlin
... import android.support.v4.app.Fragment import android.support.v4.app.LoaderManager import android.widget.AdapterView ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Java
... import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.widget.AdapterView; ... public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Определение глобальных переменных
Определите глобальные переменные, которые используются в других частях кода:
Kotlin
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private val FROM_COLUMNS: Array<String> = arrayOf( if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY } else { ContactsContract.Contacts.DISPLAY_NAME } ) /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private val TO_IDS: IntArray = intArrayOf(android.R.id.text1) ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { ... // Define global mutable variables // Define a ListView object lateinit var contactsList: ListView // Define variables for the contact the user selects // The contact's _ID value var contactId: Long = 0 // The contact's LOOKUP_KEY var contactKey: String? = null // A content URI for the selected contact var contactUri: Uri? = null // An adapter that binds the result Cursor to the ListView private val cursorAdapter: SimpleCursorAdapter? = null
Java
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private final static String[] FROM_COLUMNS = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME }; /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private final static int[] TO_IDS = { android.R.id.text1 }; // Define global mutable variables // Define a ListView object ListView contactsList; // Define variables for the contact the user selects // The contact's _ID value long contactId; // The contact's LOOKUP_KEY String contactKey; // A content URI for the selected contact Uri contactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter cursorAdapter; ...
Примечание. Поскольку для элемента Contacts.DISPLAY_NAME_PRIMARY требуется Android 3.0 (API версии 11) или более поздней версии, если для элемента minSdkVersion в приложении задано значение 10 или ниже, в Android Studio будет сгенерировано предупреждение Android Lint. Чтобы отключить это предупреждение, добавьте аннотацию @SuppressLint("InlinedApi") перед определением FROM_COLUMNS.
Инициализация фрагмента
Инициализируйте Fragment. Добавьте пустой общедоступный конструктор, необходимый для системы Android, и разверните пользовательский интерфейс объекта Fragment в методе обратного вызова onCreateView().
Пример:
Kotlin
// A UI Fragment must inflate its View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false) }
Java
// Empty public constructor, required by the system public ContactsFragment() {} // A UI Fragment must inflate its View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false); }
Настройка CursorAdapter для ListView
Настройте SimpleCursorAdapter, который связывает результаты поиска с ListView. Чтобы получить объект ListView, который показывает контакты, вызовите Activity.findViewById(), используя родительское действие Fragment. При вызове setAdapter() используйте Context родительского класса activity.
Пример:
Kotlin
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) ... // Gets the ListView from the View list of the parent activity activity?.also { contactsList = it.findViewById<ListView>(R.id.contact_list_view) // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView contactsList.adapter = cursorAdapter } }
Java
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity contactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView contactsList.setAdapter(cursorAdapter); }
Как задать слушателя выбранного контакта
Когда вы показываете результаты поиска, обычно нужно разрешить пользователю выбрать один контакт для дальнейшей обработки. Например, когда пользователь нажимает на контакт, вы можете показать его адрес на карте. Чтобы реализовать эту функцию, сначала определите текущий объект Fragment как прослушиватель кликов, указав, что класс реализует AdapterView.OnItemClickListener, как показано в разделе Определение фрагмента, который отображает список контактов.
Чтобы продолжить настройку прослушивателя, привяжите его к ListView, вызвав метод setOnItemClickListener() в onActivityCreated(). Пример:
Kotlin
fun onActivityCreated(savedInstanceState:Bundle) { ... // Set the item click listener to be the current fragment. contactsList.onItemClickListener = this ... }
Java
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. contactsList.setOnItemClickListener(this); ... }
Поскольку вы указали, что текущий класс Fragment является OnItemClickListener для ListView, теперь вам нужно реализовать его обязательный метод onItemClick(), который обрабатывает событие клика. Подробнее об этом рассказывается в следующем разделе.
Как определить проекцию
Определите константу, которая содержит столбцы, которые вы хотите вернуть из запроса. Каждый элемент в ListView содержит отображаемое название контакта, которое является основной формой имени контакта. В Android 3.0 (API версии 11) и более поздних версиях этот столбец называется Contacts.DISPLAY_NAME_PRIMARY, а в более ранних версиях – Contacts.DISPLAY_NAME.
Столбец Contacts._ID используется в процессе привязки SimpleCursorAdapter.
Contacts._ID и LOOKUP_KEY используются вместе для создания URI контента для контакта, выбранного пользователем.
Kotlin
... @SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Contacts.DISPLAY_NAME_PRIMARY else ContactsContract.Contacts.DISPLAY_NAME )
Java
... @SuppressLint("InlinedApi") private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME };
Define constants for the Cursor column indexes
Чтобы получить данные из отдельного столбца в Cursor, вам нужен индекс столбца в Cursor. Вы можете определить константы для индексов столбцов Cursor, поскольку индексы совпадают с порядком названий столбцов в проекции. Пример:
Kotlin
// The column index for the _ID column private const val CONTACT_ID_INDEX: Int = 0 // The column index for the CONTACT_KEY column private const val CONTACT_KEY_INDEX: Int = 1
Java
// The column index for the _ID column private static final int CONTACT_ID_INDEX = 0; // The column index for the CONTACT_KEY column private static final int CONTACT_KEY_INDEX = 1;
Укажите критерии выбора
Чтобы указать, какие данные вам нужны, создайте сочетание текстовых выражений и переменных, которые сообщают поставщику, в каких столбцах искать и какие значения находить.
Для текстового выражения определите константу, в которой перечислены столбцы поиска. Хотя это выражение может содержать и значения, рекомендуется использовать вместо них символ "?". При получении данных плейсхолдер заменяется значениями из массива. Использование символа "?" в качестве плейсхолдера гарантирует, что спецификация поиска будет создана путем привязки, а не компиляции SQL. Это исключает возможность вредоносного внедрения SQL-кода. Пример:
Kotlin
// Defines the text expression @SuppressLint("InlinedApi") private val SELECTION: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?" else "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?" ... // Defines a variable for the search string private val searchString: String = ... // Defines the array to hold values that replace the ? private val selectionArgs = arrayOf<String>(searchString)
Java
// Defines the text expression @SuppressLint("InlinedApi") private static final String SELECTION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" : Contacts.DISPLAY_NAME + " LIKE ?"; // Defines a variable for the search string private String searchString; // Defines the array to hold values that replace the ? private String[] selectionArgs = { searchString };
Определите метод onItemClick()
В предыдущем разделе вы настроили прослушиватель кликов по элементам для ListView.
Теперь реализуйте действие для прослушивателя, определив метод AdapterView.OnItemClickListener.onItemClick():
Kotlin
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) { // Get the Cursor val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply { // Move to the selected contact moveToPosition(position) // Get the _ID value contactId = getLong(CONTACT_ID_INDEX) // Get the selected LOOKUP KEY contactKey = getString(CONTACT_KEY_INDEX) // Create the contact's content Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey) /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ } }
Java
@Override public void onItemClick( AdapterView<?> parent, View item, int position, long rowID) { // Get the Cursor Cursor cursor = parent.getAdapter().getCursor(); // Move to the selected contact cursor.moveToPosition(position); // Get the _ID value contactId = cursor.getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY contactKey = cursor.getString(CONTACT_KEY_INDEX); // Create the contact's content Uri contactUri = Contacts.getLookupUri(contactId, mContactKey); /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ }
Инициализация загрузчика
Поскольку для получения данных используется CursorLoader, необходимо инициализировать фоновый поток и другие переменные, управляющие асинхронным получением. Выполните инициализацию в onCreate(), как показано в следующем примере:
Kotlin
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { // Always call the super method first super.onCreate(savedInstanceState) ... // Initializes the loader loaderManager.initLoader(0, null, this)
Java
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onCreate(Bundle savedInstanceState) { // Always call the super method first super.onCreate(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
Реализация onCreateLoader()
Реализуйте метод onCreateLoader(), который вызывается фреймворком загрузчика сразу после вызова метода initLoader().
В onCreateLoader() настройте шаблон строки поиска. Чтобы превратить строку в шаблон, вставьте символы "%" (процент), которые будут представлять последовательность из нуля или более символов, или символы "_" (подчеркивание), которые будут представлять один символ, или и то, и другое. Например, шаблон "%Jefferson%" будет соответствовать как "Thomas Jefferson", так и "Jefferson Davis".
Возвращает новый объект CursorLoader из метода. Для URI контента используйте Contacts.CONTENT_URI.
Этот URI относится ко всей таблице, как показано в следующем примере:
Kotlin
... override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%$mSearchString%" // Starts the query return activity?.let { return CursorLoader( it, ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%" + searchString + "%"; // Starts the query return new CursorLoader( getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
Реализуйте onLoadFinished() и onLoaderReset()
Реализуйте метод onLoadFinished(). Фреймворк загрузчика вызывает
onLoadFinished()
когда поставщик контактов возвращает результаты запроса. В этом методе результат Cursor помещается в SimpleCursorAdapter. После этого в ListView автоматически появятся результаты поиска:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter.swapCursor(cursor); }
Метод onLoaderReset() вызывается, когда фреймворк загрузчика обнаруживает, что результат Cursor содержит устаревшие данные. Удалите ссылку SimpleCursorAdapter на существующий объект Cursor. В противном случае фреймворк загрузчика не будет повторно использовать Cursor, что приведет к утечке памяти. Пример:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { // Delete the reference to the existing Cursor cursorAdapter?.swapCursor(null) }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor cursorAdapter.swapCursor(null); }
Теперь у вас есть основные компоненты приложения, которое сопоставляет поисковый запрос с именами контактов и возвращает результат в виде ListView. Пользователь может нажать на имя контакта, чтобы выбрать его.
Это активирует прослушиватель, в котором вы можете продолжить работу с данными контакта. Например, вы можете получить сведения о контакте. Чтобы узнать, как это сделать, перейдите к следующему уроку Получение сведений о контакте.
Подробнее о пользовательских интерфейсах поиска рассказывается в руководстве по API.
В остальных разделах этого урока показаны другие способы поиска контактов в поставщике контактов.
Как найти контакт по определенному типу данных
Этот метод позволяет указать тип данных, которые вы хотите сопоставить. Поиск по имени – это частный случай такого запроса, но вы можете выполнять его для любого типа подробных данных, связанных с контактом. Например, вы можете получить контакты с определенным почтовым индексом. В этом случае строка поиска должна соответствовать данным, хранящимся в строке почтового индекса.
Чтобы реализовать этот тип извлечения, сначала реализуйте следующий код, как описано в предыдущих разделах:
- Запросите разрешение на чтение данных поставщика.
- Определите макеты ListView и элементов.
- Определите фрагмент, который отображает список контактов.
- Определите глобальные переменные.
- Инициализируйте фрагмент.
- Настройте CursorAdapter для ListView.
- Настройте прослушиватель выбранного контакта.
-
Определите константы для индексов столбцов курсора.
Хотя вы извлекаете данные из другой таблицы, порядок столбцов в проекции остается прежним, поэтому вы можете использовать те же индексы для курсора.
- Определите метод onItemClick().
- Инициализируйте загрузчик.
- Реализуйте onLoadFinished() и onLoaderReset().
Ниже показано, как добавить код, который будет сопоставлять поисковый запрос с определенным типом данных и показывать результаты.
Выберите тип данных и таблицу
Чтобы найти определенный тип подробных данных, необходимо знать значение специального MIME-типа для этого типа данных. У каждого типа данных есть уникальное значение MIME-типа, определяемое константой CONTENT_ITEM_TYPE в подклассе ContactsContract.CommonDataKinds, связанном с типом данных.
Названия подклассов указывают на тип данных. Например, подкласс для данных электронной почты – ContactsContract.CommonDataKinds.Email, а специальный MIME-тип для данных электронной почты определяется константой Email.CONTENT_ITEM_TYPE.
Используйте для поиска таблицу ContactsContract.Data. Все константы, необходимые для проекции, предложения выбора и порядка сортировки, определены в этой таблице или унаследованы от нее.
Как задать проекцию
Чтобы определить проекцию, выберите один или несколько столбцов, определенных в ContactsContract.Data, или классы, от которых он наследуется. Перед возвратом строк поставщик контактов выполняет неявное объединение таблицы ContactsContract.Data с другими таблицами. Пример:
Kotlin
@SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Data.DISPLAY_NAME_PRIMARY else ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY )
Java
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact };
Как задать критерии поиска
Чтобы найти строку в определенном типе данных, создайте предложение выбора из следующих элементов:
-
Название столбца, содержащего строку поиска. Это название зависит от типа данных, поэтому вам нужно найти подкласс
ContactsContract.CommonDataKinds, соответствующий типу данных, а затем выбрать название столбца из этого подкласса. Например, для поиска адресов электронной почты используйте столбецEmail.ADDRESS. - Сама строка поиска, представленная символом "?" в предложении выбора.
-
Название столбца, содержащего значение специального MIME-типа. Это название всегда имеет значение
Data.MIMETYPE. -
Значение специального MIME-типа для типа данных. Как описано выше, это константа
CONTENT_ITEM_TYPEв подклассеContactsContract.CommonDataKinds. Например, значение MIME-типа для данных электронной почты –Email.CONTENT_ITEM_TYPE. Заключите значение в одинарные кавычки, добавив символ'в начале и в конце константы. В противном случае поставщик будет интерпретировать значение как имя переменной, а не как строковое значение. Вам не нужно использовать плейсхолдер для этого значения, поскольку вы используете константу, а не значение, предоставленное пользователем.
Пример:
Kotlin
/* * Constructs search criteria from the search string * and email MIME type */ private val SELECTION: String = /* * Searches for an email address * that matches the search string */ "${Email.ADDRESS} LIKE ? AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
Java
/* * Constructs search criteria from the search string * and email MIME type */ private static final String SELECTION = /* * Searches for an email address * that matches the search string */ Email.ADDRESS + " LIKE ? " + "AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
Затем определите переменные, которые будут содержать аргумент выбора:
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
Реализация onCreateLoader()
Теперь, когда вы указали, какие данные вам нужны и как их найти, определите запрос в реализации onCreateLoader().
Верните новый объект CursorLoader из этого метода, используя в качестве аргументов проекцию, текстовое выражение выбора и массив выбора. Для URI контента используйте Data.CONTENT_URI. Пример:
Kotlin
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // OPTIONAL: Makes search string into pattern searchString = "%$mSearchString%" searchString?.also { // Puts the search string into the selection criteria selectionArgs[0] = it } // Starts the query return activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern searchString = "%" + searchString + "%"; // Puts the search string into the selection criteria selectionArgs[0] = searchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
Эти фрагменты кода являются основой для базового обратного поиска на основе определенного типа подробных данных. Этот способ лучше всего подходит, если ваше приложение работает с определенным типом данных, например электронными письмами, и вы хотите, чтобы пользователи могли получать имена, связанные с этими данными.
Сопоставление контактов по любому типу данных
При поиске контакта по любому типу данных возвращаются контакты, у которых есть совпадения с поисковым запросом, включая имя, адрес электронной почты, почтовый адрес, номер телефона и т. д. В результате вы получите широкий набор результатов поиска. Например, если строка поиска – "Иванов", то при поиске по любому типу данных будет найден контакт "Иван Иванов", а также контакты, которые живут на улице Иванова.
Чтобы реализовать этот тип извлечения, сначала реализуйте следующий код, как описано в предыдущих разделах:
- Запросите разрешение на чтение данных поставщика.
- Определите макеты ListView и элементов.
- Определите фрагмент, который отображает список контактов.
- Определите глобальные переменные.
- Инициализируйте фрагмент.
- Настройте CursorAdapter для ListView.
- Настройте прослушиватель выбранного контакта.
- Определите проекцию.
-
Определите константы для индексов столбцов курсора.
Для этого типа поиска используется та же таблица, что и в разделе Как найти контакт по имени и посмотреть результаты. Используйте те же индексы столбцов.
- Определите метод onItemClick().
- Инициализируйте загрузчик.
- Реализуйте onLoadFinished() и onLoaderReset().
Ниже показано, как добавить код, который будет сопоставлять поисковый запрос с любым типом данных и показывать результаты.
Удалить критерии отбора
Не определяйте константы SELECTION и переменную mSelectionArgs.
Они не используются при этом типе поиска.
Реализация onCreateLoader()
Реализуйте метод onCreateLoader(), возвращающий новый объект CursorLoader.
Преобразовывать строку поиска в шаблон не нужно, так как поставщик контактов делает это автоматически. Используйте Contacts.CONTENT_FILTER_URI в качестве базового URI и добавьте к нему строку поиска, вызвав Uri.withAppendedPath(). При использовании этого URI автоматически запускается поиск по всем типам данных, как показано в следующем примере:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ val contentUri: Uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(searchString) ) // Starts the query return activity?.let { CursorLoader( it, contentUri, PROJECTION2, null, null, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ Uri contentUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, Uri.encode(searchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
Эти фрагменты кода являются основой приложения, которое выполняет широкий поиск в поставщике контактов. Этот метод полезен для приложений, в которых нужно реализовать функциональность, аналогичную экрану списка контактов приложения "Люди".