Z tego samouczka dowiesz się, jak pobrać listę kontaktów, których dane pasują do całego ciągu wyszukiwania lub jego części, korzystając z tych technik:
- Dopasowywanie nazw kontaktów
- Pobierz listę kontaktów, dopasowując ciąg wyszukiwania do wszystkich lub części danych nazwy kontaktu. Dostawca kontaktów zezwala na występowanie wielu wystąpień tej samej nazwy, więc ta technika może zwrócić listę dopasowań.
- dopasowanie do określonego typu danych, np. numeru telefonu;
- Pobierz listę kontaktów, dopasowując ciąg wyszukiwania do określonego typu danych, np. adresu e-mail. Dzięki temu możesz na przykład wyświetlić listę wszystkich kontaktów, których adresy e-mail pasują do ciągu wyszukiwania.
- Dopasuj dowolny typ danych
- Pobierz listę kontaktów, dopasowując ciąg wyszukiwania do dowolnego typu danych szczegółowych, w tym imienia i nazwiska, numeru telefonu, adresu ulicy, adresu e-mail itp. Na przykład ta technika umożliwia akceptowanie dowolnego typu danych dla ciągu wyszukiwania, a następnie wyświetlanie listy kontaktów, których dane pasują do tego ciągu.
Uwaga: wszystkie przykłady w tym samouczku używają funkcji CursorLoader
do pobierania danych z usługi Dostawca kontaktów. CursorLoader
wykonuje zapytanie w wątku, który jest oddzielony od wątku interfejsu. Dzięki temu zapytanie nie wydłuży czasu odpowiedzi interfejsu użytkownika i nie pogorszy wrażenia użytkowników. Więcej informacji znajdziesz w sesji szkoleniowej na temat Androida
Załadowanie danych w tle.
Prośba o dostęp do odczytu dostawcy
Aby można było wyszukiwać informacje o dostawcy kontaktów, aplikacja musi mieć uprawnienie READ_CONTACTS
.
Aby to zrobić, dodaj ten element <uses-permission>
do pliku manifestu jako element podrzędny elementu <manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Dopasowywanie kontaktu według nazwy i wyświetlanie wyników
Ta metoda próbuje dopasować ciąg wyszukiwania do nazwy kontaktu lub kontaktów w tabeli ContactsContract.Contacts
dostawcy kontaktów. Zazwyczaj warto wyświetlać wyniki w oknie ListView
, aby umożliwić użytkownikowi wybranie spośród dopasowanych kontaktów.
Definiowanie układów ListView i elementów
Aby wyświetlać wyniki wyszukiwania w ListView
, potrzebujesz głównego pliku układu, który definiuje cały interfejs użytkownika, w tym ListView
, oraz pliku układu elementu, który definiuje jeden wiersz ListView
. Możesz na przykład utworzyć główny plik układu res/layout/contacts_list_view.xml
z tym kodem 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"/>
Ten kod XML używa wbudowanego widżetu ListView
na Androida.
android:id/list
Zdefiniuj plik układu produktu contacts_list_item.xml
za pomocą tego kodu 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"/>
Ten kod XML używa wbudowanego widżetu TextView
na Androida.
android:text1
Uwaga: ta lekcja nie opisuje interfejsu użytkownika do pobierania ciągu wyszukiwania od użytkownika, bo może się zdarzyć, że konieczne będzie uzyskanie tego ciągu znaków pośrednio. Możesz na przykład umożliwić użytkownikowi wyszukiwanie kontaktów, których nazwa pasuje do ciągu znaków w przychodzącej wiadomości tekstowej.
Oba utworzone przez Ciebie pliki układu definiują interfejs użytkownika, który wyświetlaListView
. Kolejnym krokiem jest napisanie kodu, który używa tego interfejsu do wyświetlania listy kontaktów.
Zdefiniuj fragment wyświetlający listę kontaktów
Aby wyświetlić listę kontaktów, zacznij od zdefiniowania Fragment
, który jest wczytywany przez Activity
. Użycie Fragment
jest bardziej elastycznym rozwiązaniem, ponieważ możesz użyć jednego Fragment
do wyświetlenia listy, a drugiego Fragment
do wyświetlenia szczegółów kontaktu, który użytkownik wybierze z listy. Dzięki temu możesz połączyć jedną z technik przedstawionych w tym samouczku z jedną z technik z samouczku
Pobieranie szczegółów kontaktu.
Aby dowiedzieć się, jak używać co najmniej jednego obiektu Fragment
z poziomu Activity
, przeczytaj zajęcia szkoleniowe
Tworzenie dynamicznego interfejsu użytkownika za pomocą fragmentów.
Aby ułatwić pisanie zapytań dotyczących dostawcy kontaktów, platforma Androida udostępnia klasę umów o nazwie ContactsContract
, która definiuje przydatne stałe i metody dostępu do dostawcy. Korzystając z tej klasy, nie musisz definiować własnych stałych dotyczących URI treści, nazw tabel ani kolumn. Aby korzystać z tej klasy,
dodaj to oświadczenie:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
Ponieważ kod używa funkcji CursorLoader
do pobierania danych od dostawcy, musisz określić, że implementuje interfejs ładowarki:LoaderManager.LoaderCallbacks
. Poza tym, aby ułatwić wykrywanie kontaktu wybranego przez użytkownika z listy wyników wyszukiwania, zaimplementuj interfejs adaptera AdapterView.OnItemClickListener
. Na przykład:
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 {
Definiowanie zmiennych globalnych
Definiowanie zmiennych globalnych, które są używane w innych częściach kodu:
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; ...
Uwaga: Contacts.DISPLAY_NAME_PRIMARY
wymaga Androida w wersji 3.0 (interfejs API w wersji 11) lub nowszej, dlatego ustawienie minSdkVersion
aplikacji na 10 lub mniej powoduje wygenerowanie ostrzeżenia Android Lint w Android Studio. Aby wyłączyć to ostrzeżenie, przed definicją FROM_COLUMNS
dodaj adnotację
@SuppressLint("InlinedApi")
.
Inicjowanie fragmentu
Inicjalizacja Fragment
. Dodaj pusty, publiczny konstruktor wymagany przez system Android i zwiększ interfejs użytkownika obiektu Fragment
w metodzie wywołania zwrotnego onCreateView()
.
Na przykład:
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); }
Konfigurowanie CursorAdaptera dla ListView
Skonfiguruj SimpleCursorAdapter
, który łączy wyniki wyszukiwania z elementem ListView
. Aby uzyskać obiekt ListView
, który wyświetla kontakty, musisz wywołać Activity.findViewById()
, używając aktywności nadrzędnej obiektu Fragment
. Gdy wywołujesz setAdapter()
, używaj Context
aktywności nadrzędnej.
Na przykład:
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); }
Ustaw odbiornik wybranego kontaktu
Wyświetlając wyniki wyszukiwania, zwykle chcesz umożliwić użytkownikowi wybranie jednego kontaktu do dalszego przetwarzania. Gdy użytkownik kliknie kontakt, możesz wyświetlić jego adres na mapie. Aby udostępnić tę funkcję, musisz najpierw zdefiniować bieżący Fragment
jako detektor kliknięć, określając, że klasa implementuje AdapterView.OnItemClickListener
, jak pokazano w sekcji Definiowanie fragmentu, który wyświetla listę kontaktów.
Aby kontynuować konfigurowanie listenera, powiązać go z ListView
, wywołując metodę setOnItemClickListener()
w onActivityCreated()
. Na przykład:
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); ... }
Ponieważ określiłeś/aś, że bieżąca wartość Fragment
jest wartościąOnItemClickListener
dla ListView
, musisz teraz zaimplementować wymaganą metodę onItemClick()
, która obsługuje zdarzenie kliknięcia. Jest to opisane w następnej sekcji.
Definiowanie projekcji
Zdefiniuj stałą zawierającą kolumny, które mają być zwracane przez zapytanie. Każdy element w ListView
zawiera wyświetlaną nazwę kontaktu, która zawiera główną formę nazwy kontaktu. W Androidzie 3.0 (wersja interfejsu API 11) i nowszych ta kolumna ma nazwę Contacts.DISPLAY_NAME_PRIMARY
, a w poprzednich wersjach nazwa tej kolumny to Contacts.DISPLAY_NAME
.
Kolumna Contacts._ID
jest używana w procesie powiązania SimpleCursorAdapter
.
Wartości Contacts._ID
i LOOKUP_KEY
są używane razem do tworzenia identyfikatora URI treści dla wybranego przez użytkownika kontaktu.
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 };
Definiowanie stałych wartości dla indeksów kolumny Cursor
Aby uzyskać dane z pojedynczej kolumny w tablicy Cursor
, musisz podać indeks tej kolumny w tablicy Cursor
. Możesz zdefiniować stałe dla indeksów kolumn Cursor
, ponieważ indeksy są takie same jak kolejność nazw kolumn w projekcji. Na przykład:
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;
Określ kryteria wyboru
Aby określić dane, które Cię interesują, utwórz kombinację wyrażeń tekstowych i zmiennych, które informują dostawcę o tym, w których kolumnach danych ma szukać i jakich wartości.
W przypadku wyrażenia tekstowego zdefiniuj stałą, która zawiera listę kolumn wyszukiwania. Chociaż to wyrażenie może też zawierać wartości, zaleca się, aby wartości były reprezentowane za pomocą zastępnika „?”. Podczas pobierania obiekt zastępczy jest zastępowany wartościami z tablicy. Użycie znaku „?” jako zastępnika zapewnia, że specyfikacja wyszukiwania jest generowana przez powiązanie, a nie przez kompilację SQL. Dzięki temu eliminowana jest możliwość wstrzyknięcia złośliwego kodu SQL. Na przykład:
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 };
Zdefiniuj metodę onItemClick()
W poprzedniej sekcji ustawiliśmy dla elementu ListView
listenera kliknięcia elementu.
Teraz zaimplementuj działanie dla odbiornika, definiując metodę 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. */ }
Inicjowanie ładowarki
Ponieważ do pobierania danych używasz CursorLoader
, musisz zainicjować wątek w tle i inne zmienne, które kontrolują asynchroniczne pobieranie. Wykonaj inicjalizację w funkcji onCreate()
, jak w tym przykładzie:
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);
Implementacja metody onCreateLoader()
Zaimplementuj metodę onCreateLoader()
, która jest wywoływana przez mechanizm ładowarki natychmiast po wywołaniu metody initLoader()
.
W onCreateLoader()
skonfiguruj wzór ciągu wyszukiwania. Aby zmienić ciąg znaków w wzór, wstaw znaki „%” (procenty) reprezentujące sekwencję co najmniej 1 znaku lub znaki „_” (podkreślenie) reprezentujące pojedynczy znak. Na przykład wzorzec „%Jefferson%” będzie pasował do zarówno haseł „Jefferson”, jak i „Jan Kowalski”.
Zwraca nową wartość CursorLoader
z metody. W przypadku identyfikatora URI treści użyj wartości Contacts.CONTENT_URI
.
Identyfikator URI odnosi się do całej tabeli, tak jak w tym przykładzie:
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 ); }
Implementacja onLoadFinished() i onLoaderReset()
Zaimplementuj metodę onLoadFinished()
. Gdy dostawca kontaktów zwróci wyniki zapytania, framework ładowarki wywoła funkcję
onLoadFinished()
W tej metodzie umieść wynik Cursor
w elemencie SimpleCursorAdapter
. Spowoduje to automatyczne zaktualizowanie pola
ListView
z wynikami wyszukiwania:
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); }
Metoda onLoaderReset()
jest wywoływana, gdy platforma wczytywania wykryje, że wynik Cursor
zawiera nieaktualne dane. Usuń odwołanie do istniejącego pliku SimpleCursorAdapter
w pliku Cursor
. W przeciwnym razie framework loadera nie będzie mógł ponownie użyć obiektu Cursor
, co spowoduje wyciek pamięci. Na przykład:
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); }
Masz już kluczowe elementy aplikacji, która dopasowuje ciąg wyszukiwania do nazw kontaktów i zwraca wynik w komponencie ListView
. Użytkownik może kliknąć nazwę kontaktu, aby ją wybrać.
Spowoduje to wywołanie listenera, w którym możesz dalej pracować z danymi kontaktu. Możesz na przykład pobrać szczegóły kontaktu. Aby dowiedzieć się, jak to zrobić, przejdź do następnej lekcji, Pobieranie informacji o kontakcie.
Więcej informacji o interfejsach użytkownika wyszukiwarki znajdziesz w przewodniku po interfejsach API Tworzenie interfejsu wyszukiwania.
Pozostałe sekcje tego samouczka pokazują inne sposoby znajdowania kontaktów w usługach dostawców kontaktów.
Dopasowywanie kontaktu na podstawie określonego typu danych
Dzięki tej metodzie możesz określić typ danych, które chcesz dopasowywać. Pobieranie kontaktów według nazwy to konkretny przykład tego typu zapytania, ale możesz też stosować je do dowolnego typu danych szczegółowych powiązanych z kontaktem. Możesz na przykład pobrać kontakty, które mają określony kod pocztowy. W tym przypadku ciąg wyszukiwania musi pasować do danych zapisanych w wierszu kodu pocztowego.
Aby wdrożyć ten typ wyszukiwania, najpierw zastosuj ten kod, jak podano w poprzednich sekcjach:
- Poproś o uprawnienia do odczytu danych dostawcy.
- Definiowanie widoku listy i układów elementów.
- Zdefiniuj fragment, który wyświetla listę kontaktów.
- Zdefiniuj zmienne globalne.
- Zainicjuj fragment.
- Skonfiguruj CursorAdapter dla ListView.
- Ustaw odbiornik wybranego kontaktu.
-
Określ stałe dla indeksów kolumn kursora.
Chociaż pobierasz dane z innej tabeli, kolejność kolumn w prognozie jest taka sama, więc możesz używać tych samych indeksów w przypadku Kursora.
- Zdefiniuj metodę onItemClick().
- Inicjowanie ładowarki.
- Zaimplementuj metody onLoadFinished() i onLoaderReset().
W następnych krokach znajdziesz kod dodatkowy, który pozwoli Ci dopasować ciąg wyszukiwania do konkretnego typu danych szczegółowych i wyświetlić wyniki.
Wybierz typ danych i tabelę
Aby wyszukać określony typ danych szczegółowych, musisz znać niestandardową wartość typu MIME dla tego typu danych. Każdy typ danych ma unikalną wartość typu MIME zdefiniowaną przez stałą CONTENT_ITEM_TYPE
w podklasie ContactsContract.CommonDataKinds
powiązanej z typem danych.
Podklasy mają nazwy wskazujące ich typ danych. Na przykład podklasa danych e-maila to ContactsContract.CommonDataKinds.Email
, a niestandardowy typ MIME danych e-maila jest zdefiniowany przez stałą Email.CONTENT_ITEM_TYPE
.
Do wyszukiwania użyj tabeli ContactsContract.Data
. Wszystkie stałe wymagane w prognozie, klauzuli wyboru i kolejności sortowania są zdefiniowane w tej tabeli lub przez nią dziedziczone.
Definiowanie projekcji
Aby zdefiniować prognozę, wybierz co najmniej 1 kolumnę określoną w funkcji ContactsContract.Data
lub klasy, z których ona dziedziczy. Dostawca kontaktów wykonuje domyślne złączenie tabeli ContactsContract.Data
z innymi tabelami, zanim zwróci wiersze. Na przykład:
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 };
Zdefiniuj kryteria wyszukiwania
Aby wyszukać ciąg znaków w danych określonego typu, utwórz klauzulę wyboru, korzystając z tych elementów:
-
Nazwa kolumny zawierającej ciąg wyszukiwania. Nazwa ta różni się w zależności od typu danych,
dlatego musisz znaleźć podklasę
ContactsContract.CommonDataKinds
odpowiadającą typowi danych, a następnie wybrać nazwę kolumny z tej podklasy. Aby na przykład wyszukać adresy e-mail, użyj kolumnyEmail.ADDRESS
. - Sam ciąg wyszukiwania, reprezentowany przez znak „?” w klauzuli wyboru.
-
Nazwa kolumny zawierającej niestandardową wartość typu MIME. Ta nazwa jest zawsze
Data.MIMETYPE
. -
Niestandardowa wartość typu MIME dla typu danych. Jak już wspomnieliśmy, jest to stała
CONTENT_ITEM_TYPE
w podklasieContactsContract.CommonDataKinds
. Na przykład wartość typu MIME w przypadku danych poczty e-mail toEmail.CONTENT_ITEM_TYPE
. Otocz wartość cudzysłowami, łącząc znak „'
” (cudzysłów) na początku i na końcu stałej. W przeciwnym razie dostawca zinterpretuje ją jako nazwę zmiennej, a nie jako ciąg znaków. Dla tej wartości nie musisz używać symbolu zastępczego, ponieważ używasz stałej, a nie wartości podanej przez użytkownika.
Na przykład:
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 + "'";
Następnie zdefiniuj zmienne, które będą zawierać argument selection:
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
Implementacja metody onCreateLoader()
Po określeniu danych, których potrzebujesz, i sposobu ich znalezienia zdefiniuj zapytanie w implementacji usługi onCreateLoader()
.
Zwraca nową wartość CursorLoader
z tej metody, używając jako argumentów projekcji, wyrażenia tekstowego w wyborze i tablicy wyboru. W przypadku identyfikatora URI treści użyj wartości Data.CONTENT_URI
. Na przykład:
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 ); }
Te fragmenty kodu stanowią podstawę prostego wyszukiwania wstecznego na podstawie określonego typu danych szczegółowych. Jest to najlepsza metoda, jeśli Twoja aplikacja koncentruje się na określonym typie danych, np. na e-mailach, i chcesz, aby użytkownicy mogli uzyskać nazwy powiązane z danymi.
Dopasowanie kontaktu według dowolnego typu danych
Pobieranie kontaktu na podstawie dowolnego typu danych zwraca kontakty, jeśli jakiekolwiek ich dane pasują do ciągu wyszukiwania, w tym imię i nazwisko, adres e-mail, adres pocztowy, numer telefonu itp. W efekcie uzyskuje się szeroki zbiór wyników wyszukiwania. Jeśli na przykład ciąg wyszukiwania to „Nowak”, wyszukanie dowolnego typu danych zwróci kontakt „Jan Nowak”, a także kontakty z adresem „ul. Nowak”.
Aby wdrożyć ten typ wyszukiwania, najpierw zastosuj ten kod, jak podano w poprzednich sekcjach:
- Poproś o uprawnienia do odczytu danych dostawcy.
- Definiowanie widoku listy i układów elementów.
- Zdefiniuj fragment, który wyświetla listę kontaktów.
- Zdefiniuj zmienne globalne.
- Zainicjuj fragment.
- Skonfiguruj CursorAdapter dla ListView.
- Ustaw odbiornik wybranego kontaktu.
- Zdefiniuj projekcję.
-
Określ stałe dla indeksów kolumn kursora.
W przypadku tego typu pobierania używasz tej samej tabeli co w sekcji Dopasuj kontakt według imienia i nazwiska i wymień wyniki. Użyj tych samych indeksów kolumn.
- Zdefiniuj metodę onItemClick().
- Inicjowanie ładowarki.
- Zaimplementuj metody onLoadFinished() i onLoaderReset().
W następnych krokach pokażemy Ci dodatkowy kod, który umożliwi Ci dopasowanie ciągu wyszukiwania do dowolnego typu danych i wyświetlenie wyników.
Usuwanie kryteriów wyboru
Nie definiuj stałych SELECTION
ani zmiennej mSelectionArgs
.
W przypadku tego typu wyszukiwania nie są one używane.
Wdróż onCreateLoader()
Zaimplementuj metodę onCreateLoader()
, która zwraca nowy obiekt CursorLoader
.
Nie musisz konwertować ciągu wyszukiwania na wzór, ponieważ dostawca kontaktów robi to automatycznie. Użyj Contacts.CONTENT_FILTER_URI
jako podstawowego identyfikatora URI i dołącz do niego wyszukiwany ciąg, wywołując metodę Uri.withAppendedPath()
. Użycie tego identyfikatora URI automatycznie uruchamia wyszukiwanie dowolnego typu danych, jak pokazano w tym przykładzie:
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 ); }
Te fragmenty kodu stanowią podstawę aplikacji, która przeprowadza ogólne wyszukiwanie w usługodawcy kontaktów. Ta metoda jest przydatna w przypadku aplikacji, które chcą zaimplementować funkcję podobną do ekranu listy kontaktów w aplikacji Kontakty.