In dieser Lektion wird beschrieben, wie Sie mithilfe der folgenden Techniken eine Liste von Kontakten abrufen, deren Daten ganz oder teilweise mit einem Suchstring übereinstimmen:
- Kontaktnamen abgleichen
- Ruft eine Liste von Kontakten ab, indem der Suchstring mit allen oder einem Teil der Kontaktnamendaten abgeglichen wird. Der Contacts Provider erlaubt mehrere Instanzen desselben Namens, sodass diese Technik eine Liste von Übereinstimmungen zurückgeben kann.
- Abgleich mit einem bestimmten Datentyp, z. B. einer Telefonnummer
- Eine Liste von Kontakten abrufen, indem der Suchstring mit einem bestimmten Typ von Detaildaten wie einer E-Mail-Adresse abgeglichen wird. Mit dieser Methode können Sie beispielsweise alle Kontakte auflisten, deren E-Mail-Adresse mit dem Suchstring übereinstimmt.
- Mit beliebigen Datentypen abgleichen
- Eine Liste von Kontakten abrufen, indem der Suchstring mit beliebigen Detaildaten abgeglichen wird, darunter Name, Telefonnummer, Adresse, E-Mail-Adresse usw. Mit dieser Technik können Sie beispielsweise beliebige Datentypen für einen Suchstring akzeptieren und dann die Kontakte auflisten, für die die Daten mit dem String übereinstimmen.
Hinweis:In allen Beispielen in dieser Lektion wird ein CursorLoader verwendet, um Daten vom Kontaktanbieter abzurufen. Eine CursorLoader führt ihre Abfrage in einem Thread aus, der vom UI-Thread getrennt ist. So wird sichergestellt, dass die Abfrage die Reaktionszeiten der Benutzeroberfläche nicht verlangsamt und die Nutzerfreundlichkeit nicht beeinträchtigt. Weitere Informationen finden Sie im Android-Trainingskurs
Daten im Hintergrund laden.
Berechtigung zum Lesen des Anbieters anfordern
Wenn Sie den Contacts Provider durchsuchen möchten, muss Ihre App die Berechtigung READ_CONTACTS haben.
Fügen Sie dazu das folgende <uses-permission>-Element als untergeordnetes Element von <manifest> in Ihre Manifestdatei ein:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Kontakte anhand des Namens abgleichen und die Ergebnisse auflisten
Bei dieser Methode wird versucht, einen Suchstring mit dem Namen eines oder mehrerer Kontakte in der Tabelle ContactsContract.Contacts des Contacts Provider abzugleichen. Normalerweise werden die Ergebnisse in einem ListView angezeigt, damit der Nutzer zwischen den übereinstimmenden Kontakten wählen kann.
ListView- und Elementlayouts definieren
Wenn Sie die Suchergebnisse in einer ListView anzeigen möchten, benötigen Sie eine Hauptlayoutdatei, die die gesamte Benutzeroberfläche einschließlich der ListView definiert, und eine Elementlayoutdatei, die eine Zeile der ListView definiert. Sie können beispielsweise die Hauptlayoutdatei res/layout/contacts_list_view.xml mit dem folgenden XML-Code erstellen:
<?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"/>
In diesem XML-Code wird das integrierte Android-Widget ListView android:id/list verwendet.
Definieren Sie die Elementlayoutdatei contacts_list_item.xml mit dem folgenden XML-Code:
<?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"/>
In diesem XML-Code wird das integrierte Android-Widget TextView android:text1 verwendet.
Hinweis: In dieser Lektion wird nicht die Benutzeroberfläche zum Abrufen eines Suchstrings vom Nutzer beschrieben, da Sie den String möglicherweise indirekt abrufen möchten. Sie können dem Nutzer beispielsweise die Möglichkeit geben, nach Kontakten zu suchen, deren Name mit einem String in einer eingehenden Nachricht übereinstimmt.
Die beiden von Ihnen erstellten Layoutdateien definieren eine Benutzeroberfläche, die ein ListView anzeigt. Als Nächstes schreiben Sie Code, der diese Benutzeroberfläche verwendet, um eine Liste von Kontakten anzuzeigen.
Fragment definieren, in dem die Kontaktliste angezeigt wird
Wenn du die Liste der Kontakte anzeigen möchtest, musst du zuerst einen Fragment definieren, der von einem Activity geladen wird. Die Verwendung von Fragment ist flexibler, da Sie ein Fragment zum Anzeigen der Liste und ein zweites Fragment zum Anzeigen der Details für einen Kontakt verwenden können, den der Nutzer aus der Liste auswählt. Mit diesem Ansatz können Sie eine der in dieser Lektion vorgestellten Techniken mit einer aus der Lektion
Details zu einem Kontakt abrufen kombinieren.
Informationen zur Verwendung eines oder mehrerer Fragment-Objekte aus einer Activity findest du im Trainingskurs
Dynamische Benutzeroberfläche mit Fragmenten erstellen.
Damit Sie Abfragen für den Contacts Provider schreiben können, stellt das Android-Framework eine Contract-Klasse namens ContactsContract bereit, die nützliche Konstanten und Methoden für den Zugriff auf den Anbieter definiert. Wenn du diese Klasse verwendest, musst du keine eigenen Konstanten für Inhalts-URIs, Tabellennamen oder Spalten definieren. Fügen Sie die folgende Anweisung ein, um diese Klasse zu verwenden:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
Da der Code einen CursorLoader verwendet, um Daten vom Anbieter abzurufen, müssen Sie angeben, dass er die Loader-Schnittstelle LoaderManager.LoaderCallbacks implementiert. Implementiere außerdem die Adapterschnittstelle AdapterView.OnItemClickListener, um zu erkennen, welchen Kontakt der Nutzer aus der Liste der Suchergebnisse auswählt. Beispiel:
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 {
Globale Variablen definieren
Definieren Sie globale Variablen, die in anderen Teilen des Codes verwendet werden:
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; ...
Hinweis:Da für Contacts.DISPLAY_NAME_PRIMARY Android 3.0 (API-Version 11) oder höher erforderlich ist, wird in Android Studio eine Android Lint-Warnung generiert, wenn Sie für minSdkVersion Ihrer App den Wert 10 oder niedriger festlegen. Wenn Sie diese Warnung deaktivieren möchten, fügen Sie die Annotation @SuppressLint("InlinedApi") vor der Definition von FROM_COLUMNS hinzu.
Fragment initialisieren
Initialisieren Sie die Fragment. Fügen Sie den leeren, öffentlichen Konstruktor hinzu, der vom Android-System benötigt wird, und blähen Sie die Benutzeroberfläche des Fragment-Objekts in der Callback-Methode onCreateView() auf.
Beispiel:
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 für die ListView einrichten
Richten Sie die SimpleCursorAdapter ein, die die Ergebnisse der Suche an die ListView bindet. Wenn Sie das ListView-Objekt abrufen möchten, in dem die Kontakte angezeigt werden, müssen Sie Activity.findViewById() mit der übergeordneten Aktivität von Fragment aufrufen. Verwenden Sie die Context der übergeordneten Aktivität, wenn Sie setAdapter() aufrufen.
Beispiel:
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); }
Ausgewählten Kontakt-Listener festlegen
Wenn du die Ergebnisse einer Suche anzeigst, möchtest du dem Nutzer in der Regel die Möglichkeit geben, einen einzelnen Kontakt für die weitere Verarbeitung auszuwählen. Wenn der Nutzer beispielsweise auf einen Kontakt klickt, können Sie die Adresse des Kontakts auf einer Karte anzeigen. Um diese Funktion bereitzustellen, haben Sie zuerst das aktuelle Fragment als Klick-Listener definiert, indem Sie angegeben haben, dass die Klasse AdapterView.OnItemClickListener implementiert, wie im Abschnitt Fragment definieren, das die Liste der Kontakte anzeigt beschrieben.
Um die Einrichtung des Listeners fortzusetzen, binden Sie ihn an ListView, indem Sie die Methode setOnItemClickListener() in onActivityCreated() aufrufen. Beispiel:
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); ... }
Da Sie angegeben haben, dass die aktuelle Fragment der OnItemClickListener für den ListView ist, müssen Sie jetzt die erforderliche Methode onItemClick() implementieren, die das Click-Event verarbeitet. Dies wird in einem nachfolgenden Abschnitt beschrieben.
Projektion definieren
Definieren Sie eine Konstante, die die Spalten enthält, die Sie aus Ihrer Abfrage zurückgeben möchten. Für jedes Element in der ListView wird der Anzeigename des Kontakts angezeigt, der die Hauptform des Kontaktnamens enthält. In Android 3.0 (API-Version 11) und höher lautet der Name dieser Spalte Contacts.DISPLAY_NAME_PRIMARY. In früheren Versionen lautet der Name Contacts.DISPLAY_NAME.
Die Spalte Contacts._ID wird vom Bindungsprozess SimpleCursorAdapter verwendet.
Contacts._ID und LOOKUP_KEY werden zusammen verwendet, um einen Inhalts-URI für den vom Nutzer ausgewählten Kontakt zu erstellen.
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 };
Konstanten für die Cursor-Spaltenindexe definieren
Wenn Sie Daten aus einer einzelnen Spalte in einem Cursor abrufen möchten, benötigen Sie den Index der Spalte im Cursor. Sie können Konstanten für die Indexe der Cursor-Spalten definieren, da die Indexe mit der Reihenfolge der Spaltennamen in Ihrer Projektion übereinstimmen. Beispiel:
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;
Auswahlkriterien angeben
Wenn Sie die gewünschten Daten angeben möchten, erstellen Sie eine Kombination aus Textausdrücken und Variablen, die dem Anbieter mitteilen, welche Datenspalten durchsucht und welche Werte gefunden werden sollen.
Definieren Sie für den Textausdruck eine Konstante, in der die Suchspalten aufgeführt sind. Dieser Ausdruck kann zwar auch Werte enthalten, es empfiehlt sich jedoch, die Werte mit einem „?“-Platzhalter darzustellen. Beim Abruf wird der Platzhalter durch Werte aus einem Array ersetzt. Wenn Sie „?“ als Platzhalter verwenden, wird die Suchspezifikation durch Bindung und nicht durch SQL-Kompilierung generiert. Dadurch wird die Möglichkeit einer schädlichen SQL-Injection ausgeschlossen. Beispiel:
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 };
Methode onItemClick() definieren
In einem vorherigen Abschnitt haben Sie den Item-Click-Listener für die ListView festgelegt.
Implementieren Sie nun die Aktion für den Listener, indem Sie die Methode AdapterView.OnItemClickListener.onItemClick() definieren:
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. */ }
Loader initialisieren
Da Sie ein CursorLoader zum Abrufen von Daten verwenden, müssen Sie den Hintergrundthread und andere Variablen initialisieren, die den asynchronen Abruf steuern. Führen Sie die Initialisierung in onCreate() aus, wie im folgenden Beispiel gezeigt:
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() implementieren
Implementieren Sie die Methode onCreateLoader(), die vom Loader-Framework unmittelbar nach dem Aufruf von initLoader() aufgerufen wird.
Richten Sie in onCreateLoader() das Suchstringmuster ein. Wenn Sie einen String in ein Muster umwandeln möchten, fügen Sie „%“ (Prozentzeichen) ein, um eine Sequenz von null oder mehr Zeichen darzustellen, oder „_“ (Unterstrich), um ein einzelnes Zeichen darzustellen, oder beides. Das Muster „%Jefferson%“ würde beispielsweise sowohl mit „Thomas Jefferson“ als auch mit „Jefferson Davis“ übereinstimmen.
Geben Sie einen neuen CursorLoader aus der Methode zurück. Verwenden Sie für den Inhalts-URI Contacts.CONTENT_URI.
Dieser URI bezieht sich auf die gesamte Tabelle, wie im folgenden Beispiel gezeigt:
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() und onLoaderReset() implementieren
Implementieren Sie die Methode onLoadFinished(). Das Loader-Framework ruft onLoadFinished() auf, wenn der Contacts Provider die Ergebnisse der Abfrage zurückgibt. Fügen Sie in dieser Methode das Ergebnis Cursor in die SimpleCursorAdapter ein. Dadurch wird die ListView automatisch mit den Suchergebnissen aktualisiert:
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); }
Die Methode onLoaderReset() wird aufgerufen, wenn das Loader-Framework erkennt, dass das Ergebnis Cursor veraltete Daten enthält. Löschen Sie den Verweis SimpleCursorAdapter auf die vorhandene Cursor. Andernfalls wird das Cursor nicht wiederverwendet, was zu einem Speicherleck führt. Beispiel:
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); }
Sie haben jetzt die wichtigsten Teile einer App, die einen Suchstring mit Kontaktnamen abgleicht und das Ergebnis in einem ListView zurückgibt. Der Nutzer kann auf einen Kontaktnamen klicken, um ihn auszuwählen.
Dadurch wird ein Listener ausgelöst, in dem Sie die Daten des Kontakts weiter bearbeiten können. Sie können beispielsweise die Kontaktdaten abrufen. Wie das geht, erfahren Sie in der nächsten Lektion Details für einen Kontakt abrufen.
Weitere Informationen zu Such-Benutzeroberflächen finden Sie im API-Leitfaden Suchoberfläche erstellen.
In den verbleibenden Abschnitten dieser Lektion werden andere Möglichkeiten zum Suchen von Kontakten im Contacts Provider beschrieben.
Kontakte anhand eines bestimmten Datentyps abgleichen
Mit dieser Technik können Sie den Typ der Daten angeben, die abgeglichen werden sollen. Das Abrufen nach Name ist ein konkretes Beispiel für diese Art von Abfrage. Sie können sie aber auch für alle Arten von Detaildaten verwenden, die mit einem Kontakt verknüpft sind. Sie können beispielsweise Kontakte mit einer bestimmten Postleitzahl abrufen. In diesem Fall muss der Suchstring mit den Daten in einer Postleitzahlzeile übereinstimmen.
Um diese Art des Abrufs zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie in den vorherigen Abschnitten beschrieben:
- Berechtigung zum Lesen des Anbieters anfordern
- ListView- und Elementlayouts definieren
- Definieren Sie ein Fragment, das die Liste der Kontakte anzeigt.
- Globale Variablen definieren
- Initialisieren Sie das Fragment.
- Richten Sie den CursorAdapter für die ListView ein.
- Legen Sie den ausgewählten Kontakt-Listener fest.
-
Definiere Konstanten für die Cursor-Spaltenindexe.
Obwohl Sie Daten aus einer anderen Tabelle abrufen, ist die Reihenfolge der Spalten in der Projektion dieselbe. Sie können also dieselben Indexe für den Cursor verwenden.
- Definieren Sie die Methode „onItemClick()“.
- Initialisieren Sie das Ladeprogramm.
- Implementieren Sie „onLoadFinished()“ und „onLoaderReset()“.
In den folgenden Schritten wird der zusätzliche Code gezeigt, den Sie benötigen, um einen Suchstring mit einem bestimmten Typ von Detaildaten abzugleichen und die Ergebnisse anzuzeigen.
Datentyp und Tabelle auswählen
Wenn Sie nach einem bestimmten Typ von Detaildaten suchen möchten, müssen Sie den benutzerdefinierten MIME-Typwert für den Datentyp kennen. Jeder Datentyp hat einen eindeutigen MIME-Typwert, der durch eine Konstante CONTENT_ITEM_TYPE in der Unterklasse von ContactsContract.CommonDataKinds definiert wird, die dem Datentyp zugeordnet ist.
Die Namen der Unterklassen geben ihren Datentyp an. Die Unterklasse für E-Mail-Daten ist beispielsweise ContactsContract.CommonDataKinds.Email und der benutzerdefinierte MIME-Typ für E-Mail-Daten wird durch die Konstante Email.CONTENT_ITEM_TYPE definiert.
Verwenden Sie für Ihre Suche die Tabelle ContactsContract.Data. Alle Konstanten, die du für die Projektion, die Auswahlklausel und die Sortierreihenfolge benötigst, sind in dieser Tabelle definiert oder werden von ihr übernommen.
Projektion definieren
Um eine Projektion zu definieren, wählen Sie eine oder mehrere der in ContactsContract.Data definierten Spalten oder die Klassen aus, von denen sie erbt. Der Contacts Provider führt einen impliziten Join zwischen ContactsContract.Data und anderen Tabellen aus, bevor er Zeilen zurückgibt. Beispiel:
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 };
Suchkriterien definieren
Wenn Sie nach einem String in einem bestimmten Datentyp suchen möchten, erstellen Sie eine Auswahlklausel aus den folgenden Elementen:
-
Der Name der Spalte, die den Suchstring enthält. Dieser Name variiert je nach Datentyp. Sie müssen also die Unterklasse von
ContactsContract.CommonDataKindsfinden, die dem Datentyp entspricht, und dann den Spaltennamen aus dieser Unterklasse auswählen. Wenn Sie beispielsweise nach E‑Mail-Adressen suchen möchten, verwenden Sie die SpalteEmail.ADDRESS. - Der Suchstring selbst, dargestellt als das Fragezeichen „?“ in der Auswahlklausel.
-
Der Name der Spalte, die den benutzerdefinierten MIME-Typwert enthält. Dieser Name ist immer
Data.MIMETYPE. -
Der benutzerdefinierte MIME-Typwert für den Datentyp. Wie bereits beschrieben, ist dies die Konstante
CONTENT_ITEM_TYPEin der UnterklasseContactsContract.CommonDataKinds. Der MIME-Typ für E-Mail-Daten ist beispielsweiseEmail.CONTENT_ITEM_TYPE. Setzen Sie den Wert in einfache Anführungszeichen, indem Sie am Anfang und Ende der Konstanten das Zeichen „'“ (einfaches Anführungszeichen) einfügen. Andernfalls interpretiert der Anbieter den Wert als Variablennamen und nicht als Stringwert. Sie müssen für diesen Wert keinen Platzhalter verwenden, da Sie eine Konstante und keinen vom Nutzer bereitgestellten Wert verwenden.
Beispiel:
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 + "'";
Definieren Sie als Nächstes Variablen, die das Auswahlargument enthalten:
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
onCreateLoader() implementieren
Nachdem Sie die gewünschten Daten und die Suchmethode angegeben haben, definieren Sie eine Abfrage in Ihrer Implementierung von onCreateLoader().
Gib mit dieser Methode ein neues CursorLoader-Objekt zurück und verwende dabei deine Projektion, den Textausdruck für die Auswahl und das Array für die Auswahl als Argumente. Verwenden Sie für einen Inhalts-URI Data.CONTENT_URI. Beispiel:
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 ); }
Diese Code-Snippets bilden die Grundlage für eine einfache Rückwärtssuche auf Grundlage einer bestimmten Art von Detaildaten. Diese Methode eignet sich am besten, wenn sich Ihre App auf einen bestimmten Datentyp wie E‑Mails konzentriert und Sie Nutzern ermöglichen möchten, die mit einem Datenelement verknüpften Namen abzurufen.
Kontakt anhand eines beliebigen Datentyps abgleichen
Wenn Sie einen Kontakt anhand eines beliebigen Datentyps abrufen, werden Kontakte zurückgegeben, wenn eines ihrer Daten mit dem Suchstring übereinstimmt, z. B. Name, E-Mail-Adresse, Postanschrift, Telefonnummer usw. Das führt zu einer breiten Palette von Suchergebnissen. Wenn der Suchstring beispielsweise „Doe“ lautet, wird bei der Suche nach einem beliebigen Datentyp der Kontakt „John Doe“ zurückgegeben. Außerdem werden Kontakte zurückgegeben, die in der „Doe Street“ wohnen.
Um diese Art des Abrufs zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie in den vorherigen Abschnitten beschrieben:
- Berechtigung zum Lesen des Anbieters anfordern
- ListView- und Elementlayouts definieren
- Definieren Sie ein Fragment, das die Liste der Kontakte anzeigt.
- Globale Variablen definieren
- Initialisieren Sie das Fragment.
- Richten Sie den CursorAdapter für die ListView ein.
- Legen Sie den ausgewählten Kontakt-Listener fest.
- Definieren Sie eine Projektion.
-
Definiere Konstanten für die Cursor-Spaltenindexe.
Für diesen Abruftyp verwenden Sie dieselbe Tabelle wie im Abschnitt Kontakt anhand des Namens abgleichen und Ergebnisse auflisten. Verwenden Sie auch dieselben Spaltenindexe.
- Definieren Sie die Methode „onItemClick()“.
- Initialisieren Sie das Ladeprogramm.
- Implementieren Sie onLoadFinished() und onLoaderReset().
In den folgenden Schritten wird der zusätzliche Code gezeigt, den Sie benötigen, um einen Suchstring mit einem beliebigen Datentyp abzugleichen und die Ergebnisse anzuzeigen.
Auswahlkriterien entfernen
Definieren Sie die SELECTION-Konstanten oder die mSelectionArgs-Variable nicht.
Sie werden bei dieser Art von Abruf nicht verwendet.
onCreateLoader() implementieren
Implementieren Sie die Methode onCreateLoader(), die ein neues CursorLoader zurückgibt.
Du musst den Suchstring nicht in ein Muster umwandeln, da der Contacts Provider dies automatisch tut. Verwenden Sie Contacts.CONTENT_FILTER_URI als Basis-URI und hängen Sie Ihren Suchstring an, indem Sie Uri.withAppendedPath() aufrufen. Wenn Sie diesen URI verwenden, wird automatisch nach allen Datentypen gesucht, wie im folgenden Beispiel gezeigt:
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 ); }
Diese Code-Snippets sind die Grundlage einer App, die eine umfassende Suche im Contacts Provider durchführt. Diese Technik ist nützlich für Apps, die eine ähnliche Funktionalität wie der Bildschirm mit der Kontaktliste der Kontakte-App implementieren möchten.