In dieser Lektion erfahren Sie, wie Sie eine Liste von Kontakten abrufen, deren Daten ganz oder teilweise mit Suchzeichenfolge mit den folgenden Methoden suchen:
- Kontaktnamen abgleichen
- Liste der Kontakte abrufen, indem der Suchstring mit dem gesamten oder einem Teil der Daten des Kontaktnamens abgeglichen wird. Der Kontaktanbieter lässt mehrere Instanzen desselben Namens zu. kann eine Liste von Übereinstimmungen zurückgegeben werden.
- Übereinstimmung mit einem bestimmten Datentyp, z. B. einer Telefonnummer
- Liste mit Kontakten abrufen, indem der Suchstring mit einem bestimmten Detaildatentyp wie einer E-Mail-Adresse abgeglichen wird. So können Sie beispielsweise alle Kontakte auflisten, deren E-Mail-Adresse mit dem Suchstring übereinstimmt.
- Übereinstimmung mit jedem Datentyp
- Sie können eine Liste von Kontakten abrufen, indem Sie den Suchstring mit beliebigen Detaildaten abgleichen, z. B. Name, Telefonnummer, Adresse oder E-Mail-Adresse. So 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 eine CursorLoader
verwendet, um Daten vom Kontaktdatenanbieter abzurufen. Ein CursorLoader
führt seine Abfrage in einem Thread aus, der vom UI-Thread getrennt ist. So wird sichergestellt, dass die Abfrage die UI-Antwortzeiten nicht verlangsamt und die Nutzerfreundlichkeit nicht beeinträchtigt. Weitere Informationen finden Sie in der
Schulung
Daten im Hintergrund laden.
Berechtigung zum Lesen des Anbieters anfordern
Damit Sie mit dem Contacts Provider suchen können, muss Ihre Anwendung über
Berechtigung „READ_CONTACTS
“.
Fügen Sie dazu das Element <uses-permission>
als untergeordnetes Element von <manifest>
in Ihre Manifestdatei ein:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Kontakte nach Namen abgleichen und Ergebnisse auflisten
Mit diesem Verfahren wird versucht, eine Suchzeichenfolge mit dem Namen eines oder mehrerer Kontakte in der
Tabelle ContactsContract.Contacts
des Anbieters kontaktieren. Normalerweise sollten Sie die Ergebnisse in einer ListView
anzeigen, damit der Nutzer zwischen den übereinstimmenden Kontakten wählen kann.
ListView- und Artikellayouts definieren
Wenn Sie die Suchergebnisse in einer ListView
anzeigen möchten, benötigen Sie eine Haupt-Layoutdatei, die die gesamte Benutzeroberfläche einschließlich der ListView
definiert, und eine Artikel-Layoutdatei, die eine Zeile der ListView
definiert. Sie könnten beispielsweise
die Hauptlayoutdatei res/layout/contacts_list_view.xml
mit
den folgenden XML-Code:
<?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"/>
Dieser XML-Code verwendet das integrierte Android-Widget ListView
android:id/list
.
Definieren Sie die Artikel-Layoutdatei contacts_list_item.xml
mit der folgenden XML-Datei:
<?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 dieser XML-Datei 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 eine Option, um nach Kontakten zu suchen, deren Name mit einer Zeichenfolge in einer eingehenden SMS übereinstimmt.
Die beiden Layoutdateien, die Sie geschrieben haben, definieren eine Benutzeroberfläche, auf der ein
ListView
Der nächste Schritt besteht darin, Code zu schreiben, mit dem über diese Benutzeroberfläche ein
Liste der Kontakte.
Definieren Sie ein Fragment, das die Liste der Kontakte anzeigt
Um die Liste der Kontakte anzuzeigen, definiere zuerst einen Fragment
der von einem Activity
geladen wird. Mit einer
Fragment
ist flexibler, weil Sie
ein Fragment
, um die Liste anzuzeigen, und ein zweites
Fragment
, um die Details zu einem Kontakt aufzurufen, den der Nutzer
aus der Liste auswählt. Mit diesem Ansatz können Sie eine der Techniken kombinieren, die in
mit einem aus der Lektion
Details zu einem Kontakt abrufen
Informationen zum Verwenden eines oder mehrerer Fragment
-Objekte aus einem Activity
finden Sie im Trainingskurs Dynamic UIs mithilfe von Fragmenten erstellen.
Zum Erstellen von Abfragen an den Contacts Provider bietet das Android-Framework die Vertragsklasse ContactsContract
, die nützliche Konstanten und Methoden für den Zugriff auf den Anbieter definiert. Für diesen Kurs sind keine
eigene Konstanten für Inhalts-URIs, Tabellennamen oder Spalten definieren Wenn Sie diese Klasse verwenden möchten, fügen Sie die folgende Anweisung ein:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
Da im Code ein CursorLoader
verwendet wird, um Daten vom Anbieter abzurufen, müssen Sie angeben, dass die Ladeoberfläche LoaderManager.LoaderCallbacks
implementiert wird. Implementieren Sie außerdem die AdapteroberflächeAdapterView.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
ist Android 3.0 (API-Version 11) oder höher erforderlich.
App „minSdkVersion
auf 10 oder niedriger“ generiert eine Android Lint-Warnung in
Android Studio Fügen Sie die Anmerkung hinzu, um diese Warnung zu deaktivieren
@SuppressLint("InlinedApi")
vor der Definition von FROM_COLUMNS
.
Fragment initialisieren
Initialisieren Sie Fragment
. Leeren, öffentlichen Konstruktor hinzufügen
des Android-Systems benötigt, und blähen den Wert des Fragment
-Objekts auf,
UI in der Callback-Methode onCreateView()
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 ListView einrichten
Richten Sie die SimpleCursorAdapter
ein, die die Ergebnisse der Suche an die ListView
bindet. ListView
-Objekt abrufen
auf dem die Kontakte angezeigt werden, müssen Sie Activity.findViewById()
über die Elternaktivität der
Fragment
Verwenden Sie das Context
des
Elternaktivitäten, wenn du setAdapter()
anrufst.
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 Sie die Ergebnisse einer Suche anzeigen, möchten Sie in der Regel dem Nutzer die Auswahl eines
für die weitere Bearbeitung einen Kontakt. Wenn der Nutzer beispielsweise auf einen Kontakt klickt,
die Adresse des Kontakts auf einer Karte anzuzeigen. Um diese Funktion bereitzustellen, haben Sie zuerst die aktuelle Fragment
als Klicklistener definiert, indem Sie angegeben haben, dass die Klasse AdapterView.OnItemClickListener
implementiert, wie im Abschnitt Fragment zum Anzeigen der Kontaktliste definieren beschrieben.
Um mit der Einrichtung des Listeners fortzufahren, binden Sie ihn an ListView
, indem Sie
durch Aufrufen der Methode setOnItemClickListener()
in onActivityCreated()
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
, müssen Sie jetzt die erforderliche Methode implementieren
onItemClick()
, die
verarbeitet das Click-Event. Dies wird im nachfolgenden Abschnitt beschrieben.
Projektion definieren
Definieren Sie eine Konstante, die die Spalten enthält, die Sie von Ihrer Abfrage zurückgeben möchten. In jedem Element der ListView
wird der Anzeigename des Kontakts angezeigt, der die Hauptform des Namens des Kontakts enthält. Unter 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 SimpleCursorAdapter
-Bindungsprozess verwendet.
Contacts._ID
und LOOKUP_KEY
werden zusammen verwendet, um einen Inhalts-URI für den 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 Cursorspaltenindexe definieren
Zum Abrufen von Daten aus einer einzelnen Spalte in einem Cursor
benötigen Sie
den Index der Spalte innerhalb von Cursor
. Sie können Konstanten für die Indizes der Cursor
-Spalten definieren, da die Indizes der Reihenfolge der Spaltennamen in der Projektion entsprechen. 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 festlegen
Um die gewünschten Daten anzugeben, erstellen Sie eine Kombination aus Textausdrücken und Variablen, die dem Anbieter die zu durchsuchenden Datenspalten und die zu findenden Werte angeben.
Definieren Sie für den Textausdruck eine Konstante, die die Suchspalten auflistet. Dieser Ausdruck kann auch Werte enthalten, es wird jedoch empfohlen, die Werte durch den Platzhalter „?“ darzustellen. Beim Abrufen wird der Platzhalter durch Werte aus einem Array ersetzt. Sie verwenden "?" als Platzhalter stellt sicher, dass die Suchspezifikation durch Binden und nicht durch SQL-Kompilierung. 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 };
onItemClick()-Methode definieren
In einem vorherigen Abschnitt haben Sie den Item-Klick-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 Hintergrund-Thread und andere Variablen initialisieren, die den asynchronen
Datenabruf. 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 Lade-Framework sofort nach dem Aufruf von initLoader()
aufgerufen wird.
Im onCreateLoader()
,
Suchzeichenfolgenmuster einrichten. Wenn Sie einen String in ein Muster umwandeln möchten, fügen Sie entweder das Prozentzeichen „%“ für eine Sequenz von null oder mehr Zeichen oder das Unterstrichzeichen „_“ für ein einzelnes Zeichen ein. Sie können auch beide Zeichen verwenden. Das Muster „%Jefferson%“ würde beispielsweise sowohl mit „Thomas Jefferson“ als auch mit „Jefferson Davis“ übereinstimmen.
Gibt ein neues CursorLoader
-Objekt von der Methode zurück. Für den Inhalt
URI: Contacts.CONTENT_URI
.
Dieser URI verweist 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
onLoadFinished()
. Das Lade-Framework ruft onLoadFinished()
auf, wenn der Kontaktdatenanbieter die Ergebnisse der Abfrage zurückgibt. Bei dieser Methode geben Sie das Ergebnis Cursor
in das Feld SimpleCursorAdapter
ein. Dadurch wird die
ListView
durch die Suchergebnisse:
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 die
Ergebnis Cursor
enthält veraltete Daten. Löschen Sie die
SimpleCursorAdapter
-Verweis auf die vorhandene
Cursor
. Andernfalls wird das Loader-Framework
das Cursor
wiederverwenden, 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 einer ListView
zurückgibt. Der Nutzer kann auf den Namen eines Kontakts klicken, um ihn auszuwählen.
Dadurch wird ein Listener ausgelöst, in dem Sie mit den Daten des Kontakts weiterarbeiten können. Sie können beispielsweise die Kontaktdaten des Kontakts abrufen. Weitere Informationen dazu finden Sie in der nächsten Lektion Details für einen Kontakt abrufen.
Weitere Informationen zu Benutzeroberflächen für die Suche finden Sie im API-Leitfaden. Erstellen Sie eine Suchoberfläche.
In den verbleibenden Abschnitten dieser Lektion werden weitere Möglichkeiten zum Finden von Kontakten im Kontaktdatenanbieter gezeigt.
Kontakt anhand eines bestimmten Datentyps abgleichen
Mit diesem Verfahren können Sie den Datentyp angeben, den Sie abgleichen möchten. 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 abrufen, die eine bestimmte Postleitzahl In diesem Fall muss die Suchzeichenfolge mit Daten übereinstimmen, die in einer Postleitzahl gespeichert sind, Zeile.
Um diese Art der Abfrage zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie in den vorherigen Abschnitten aufgeführt:
- Fordern Sie die Berechtigung zum Lesen des Anbieters an.
- ListView- und Artikellayouts definieren
- Definieren Sie ein Fragment, in dem die Kontaktliste angezeigt wird.
- Definieren Sie globale Variablen.
- Initialisieren Sie das Fragment.
- Richten Sie den CursorAdapter für die ListView ein.
- Legen Sie den ausgewählten Kontakt-Listener fest.
-
Definieren Sie Konstanten für die Cursor-Spaltenindexe.
Auch wenn Sie Daten aus einer anderen Tabelle abrufen, ist die Reihenfolge der Spalten in der Projektion gleich. Sie können also dieselben Indexe für den Cursor verwenden.
- Definieren Sie die Methode „onItemClick()“.
- Initialisieren Sie den Loader.
- Implementieren Sie onLoadFinished() und onLoaderReset().
Die folgenden Schritte zeigen den zusätzlichen Code, den Sie zum Abgleichen einer Suchzeichenfolge benötigen, um eine bestimmte Art von Detaildaten und zeigen die Ergebnisse an.
Datentyp und Tabelle auswählen
Um nach einem bestimmten Detaildatentyp zu suchen, müssen Sie den benutzerdefinierten MIME-Typ-Wert kennen
für den Datentyp aus. Jeder Datentyp hat einen eindeutigen MIME-Typwert, der durch eine Konstante CONTENT_ITEM_TYPE
in der mit dem Datentyp verknüpften Unterklasse von ContactsContract.CommonDataKinds
definiert ist.
Die Namen der abgeleiteten Klassen geben ihren Datentyp an. Die abgeleitete Klasse für „email“
Daten ist ContactsContract.CommonDataKinds.Email
und das benutzerdefinierte MIME
für E-Mail-Daten durch die Konstante
Email.CONTENT_ITEM_TYPE
.
Verwenden Sie die Tabelle ContactsContract.Data
für Ihre Suche. Alle
Konstanten, die Sie für Ihre Projektion, Auswahlklausel und Sortierreihenfolge benötigen,
übernommen von dieser Tabelle.
Projektion definieren
Wählen Sie zum Definieren einer Projektion eine oder mehrere der in ContactsContract.Data
definierten Spalten oder die Klassen aus, von denen sie übernommen wird. Die
Contacts Provider führt einen impliziten Join zwischen ContactsContract.Data
durch
und andere Tabellen, bevor sie 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
Um innerhalb eines bestimmten Datentyps nach einem String zu suchen, konstruieren Sie eine Auswahlklausel aus Folgendes:
-
Der Name der Spalte, die Ihre Suchzeichenfolge enthält. Dieser Name variiert je nach Datentyp. Sie müssen also die untergeordnete Klasse von
ContactsContract.CommonDataKinds
finden, die dem Datentyp entspricht, und dann den Spaltennamen aus dieser untergeordneten Klasse auswählen. Um beispielsweise nach finden Sie in der SpalteEmail.ADDRESS
- Der Suchstring selbst, in der Auswahlklausel durch das Zeichen „?“ dargestellt.
-
Der Name der Spalte, die den benutzerdefinierten MIME-Typ enthält. Dieser Name ist immer
Data.MIMETYPE
. -
Der benutzerdefinierte MIME-Typ für den Datentyp. Wie bereits beschrieben, ist dies die Konstante
CONTENT_ITEM_TYPE
in der UnterklasseContactsContract.CommonDataKinds
. Beispiel: Das MIME- Typwert für E-Mail-Daten istEmail.CONTENT_ITEM_TYPE
Setzen Sie den Wert in einfache Anführungszeichen, indem Sie ein „'
“ (einfaches Anführungszeichen) bis zum Anfang und Ende der Konstante hinzu. Andernfalls interpretiert der Anbieter den Wert als Variablennamen und nicht als Stringwert. Für diesen Wert ist kein Platzhalter erforderlich, da Sie keine vom Nutzer bereitgestellten Werte, sondern eine Konstante 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 Methode zum Auffinden dieser Daten angegeben haben, definieren Sie eine Abfrage in Ihrer Implementierung von onCreateLoader()
.
Mit dieser Methode können Sie eine neue CursorLoader
zurückgeben. Verwenden Sie dazu die Projektion, den Ausdruck für den Auswahltext und das Auswahlarray 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 eines einfachen Reverse-Lookups basierend auf einem bestimmten Detailtyp Daten. Diese Methode eignet sich am besten, wenn sich Ihre App auf einen bestimmten Datentyp wie E-Mails konzentriert und Sie Nutzern erlauben möchten, die mit einem Datenelement verknüpften Namen abzurufen.
Kontakte anhand beliebiger Datentypen abgleichen
Beim Abrufen eines Kontakts basierend auf einem Datentyp werden Kontakte zurückgegeben, wenn deren Daten mit einem die Suchzeichenfolge, einschließlich Name, E-Mail-Adresse, Postanschrift, Telefonnummer usw. Dies führt zu einer großen Auswahl an Suchergebnissen. Wenn der Suchstring beispielsweise „Mustermann“ lautet, werden bei der Suche nach einem beliebigen Datentyp der Kontakt „Max Mustermann“ und auch Kontakte zurückgegeben, die in der „Mustermannstraße“ wohnen.
Um diese Art des Abrufs zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie unter vorherigen Abschnitten:
- Fordern Sie die Berechtigung zum Lesen des Anbieters an.
- ListView- und Artikellayouts definieren
- Definieren Sie ein Fragment, in dem die Kontaktliste angezeigt wird.
- Definieren Sie globale Variablen.
- 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.
-
Definieren Sie Konstanten für die Cursor-Spaltenindexe.
Für diese Art der Abfrage verwenden Sie dieselbe Tabelle wie im Abschnitt Kontakte nach Namen abgleichen und Ergebnisse auflisten. Verwenden Sie die Methode Spaltenindexe verwenden.
- Definieren Sie die onItemClick()-Methode.
- Initialisieren Sie den Loader.
- Implementieren Sie onLoadFinished() und onLoaderReset().
In den folgenden Schritten wird der zusätzliche Code beschrieben, der erforderlich ist, um einen Suchstring mit einem beliebigen Datentyp abzugleichen und die Ergebnisse anzuzeigen.
Auswahlkriterien entfernen
Definieren Sie die Konstanten SELECTION
oder die Variable mSelectionArgs
nicht.
Diese werden bei dieser Art der Abfrage nicht verwendet.
onCreateLoader() implementieren
Implementieren Sie die Methode onCreateLoader()
, die eine neue CursorLoader
zurückgibt.
Sie müssen die Suchzeichenfolge nicht in ein Muster konvertieren, da der Contacts Provider
automatisch. Verwenden Sie Contacts.CONTENT_FILTER_URI
als Basis-URI und hängen Sie Ihren Suchstring an, indem Sie Uri.withAppendedPath()
aufrufen. Dieser URI wird verwendet
löst automatisch die Suche nach einem beliebigen Datentyp aus, 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 bilden die Grundlage einer Anwendung, die eine umfassende Suche nach dem Contacts Provider durchführt. Diese Methode eignet sich für Apps, in denen Funktionen ähnlich wie auf dem Kontaktlistenbildschirm der Kontakte-App implementiert werden sollen.