Eine Liste von Kontakten abrufen

In dieser Lektion erfahren Sie, wie Sie mithilfe der folgenden Methoden eine Liste von Kontakten abrufen, deren Daten ganz oder teilweise mit einem Suchstring übereinstimmen:

Kontaktnamen abgleichen
Rufen Sie eine Liste von Kontakten ab, indem Sie den Suchstring mit allen oder einem Teil der Kontaktdaten des Kontakts abgleichen. Der Kontaktdatenanbieter erlaubt mehrere Instanzen desselben Namens. Daher kann diese Methode eine Liste von Übereinstimmungen zurückgeben.
Ü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 beliebigen Datentypen
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. Mit dieser Technik können Sie beispielsweise jeden Datentyp für einen Suchstring übernehmen und dann die Kontakte auflisten, bei denen 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 im Android-Trainingskurs Daten im Hintergrund laden.

Berechtigung zum Lesen des Anbieters anfordern

Damit Ihre App eine Suche im Kontaktdatenanbieter durchführen kann, benötigt sie die 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, einen Suchstring mit dem Namen eines oder mehrerer Kontakte in der Tabelle ContactsContract.Contacts des Kontaktanbieters abzugleichen. 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. So könnten Sie beispielsweise die Haupt-Layoutdatei res/layout/contacts_list_view.xml mit der folgenden XML-Datei 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 dieser XML-Datei wird das integrierte Android-Widget ListViewandroid:id/list verwendet.

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 TextViewandroid:text1 verwendet.

Hinweis:In dieser Lektion wird nicht die UI beschrieben, über die ein Suchstring vom Nutzer abgerufen wird, 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 SMS übereinstimmt.

Die beiden von Ihnen geschriebenen Layoutdateien definieren eine Benutzeroberfläche, die eine ListView anzeigt. Der nächste Schritt besteht darin, Code zu schreiben, mit dem über diese UI eine Liste von Kontakten angezeigt wird.

Definieren Sie ein Fragment, das die Liste der Kontakte anzeigt

Um die Kontaktliste anzuzeigen, müssen Sie zuerst eine Fragment definieren, die von einer Activity geladen wird. Fragment ist flexibler, da Sie mit einem Fragment die Liste und mit einem zweiten Fragment die Details für einen Kontakt aufrufen können, den der Nutzer aus der Liste auswählt. Auf diese Weise können Sie eine der in dieser Lektion vorgestellten Techniken mit einer aus der Lektion Kontaktdetails abrufen kombinieren.

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. Wenn du diese Klasse verwendest, musst du keine eigenen 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 zum Abrufen von Daten vom Anbieter verwendet wird, 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 Android 3.0 (API-Version 11) oder höher erforderlich ist, wird beim Festlegen der minSdkVersion Ihrer App auf 10 oder niedriger in Android Studio eine Android Lint-Warnung generiert. Wenn Sie diese Warnung deaktivieren möchten, fügen Sie die Anmerkung @SuppressLint("InlinedApi") vor der Definition von FROM_COLUMNS ein.

Fragment initialisieren

Initialisieren Sie Fragment. Fügen Sie den vom Android-System erforderlichen leeren öffentlichen Konstruktor hinzu und blasen 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 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 der 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 Sie die Ergebnisse einer Suche anzeigen, sollten Sie 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. Dazu haben Sie zuerst die aktuelle Fragment als Klick-Listener definiert. Dazu haben Sie angegeben, dass die Klasse AdapterView.OnItemClickListener implementiert, wie im Abschnitt Fragment definieren, das die Kontaktliste anzeigt beschrieben.

Um mit der Einrichtung des Listeners fortzufahren, binden Sie ihn an die ListView, indem Sie in onActivityCreated() die Methode setOnItemClickListener() 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 die OnItemClickListener für die ListView ist, müssen Sie jetzt die erforderliche Methode onItemClick() implementieren, die das Klickereignis verarbeitet. Dies wird in einem nachfolgenden Abschnitt beschrieben.

Projektion definieren

Definieren Sie eine Konstante, die die Spalten enthält, die Sie aus der 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. In Android 3.0 (API-Version 11) und höher lautet der Name dieser Spalte Contacts.DISPLAY_NAME_PRIMARY. In früheren Versionen ist es 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

Wenn Sie Daten aus einer einzelnen Spalte in einer Cursor abrufen möchten, benötigen Sie den Index der Spalte innerhalb der 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 angeben

Um die gewünschten Daten anzugeben, erstellen Sie eine Kombination aus Textausdrücken und Variablen, die dem Anbieter die zu suchenden Datenspalten und die zu suchenden Werte mitteilen.

Definieren Sie für den Textausdruck eine Konstante, die die Suchspalten auflistet. Dieser Ausdruck kann auch Werte enthalten, es wird jedoch empfohlen, die Werte mit dem Platzhalter „?“ darzustellen. Beim Abrufen wird der Platzhalter durch Werte aus einem Array ersetzt. Wenn Sie „?“ als Platzhalter verwenden, wird die Suchanfrage 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 };

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.
         */
    }

Lader initialisieren

Da Sie einen 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() wie im folgenden Beispiel aus:

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 unmittelbar nach dem Aufruf von initLoader() vom Loader-Framework aufgerufen wird.

Richten Sie unter onCreateLoader() das Suchstringmuster ein. Wenn Sie einen String in ein Muster umwandeln möchten, fügen Sie entweder das Prozentzeichen „%“ ein, um eine Sequenz von null oder mehr Zeichen darzustellen, oder das Unterstrichzeichen „_“, um ein einzelnes Zeichen darzustellen. Sie können auch beide Zeichen verwenden. Das Muster „%Jefferson%“ würde beispielsweise sowohl mit „Thomas Jefferson“ als auch mit „Jefferson Davis“ übereinstimmen.

Gibt eine neue 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. Bei dieser Methode geben Sie das Ergebnis Cursor in das Feld SimpleCursorAdapter ein. Dadurch werden 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 SimpleCursorAdapter-Verweis auf die vorhandene Cursor. Andernfalls wird der Cursor vom Loader-Framework 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 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 Suchoberflächen finden Sie im API-Leitfaden Suchoberfläche erstellen.

In den verbleibenden Abschnitten dieser Lektion werden weitere Möglichkeiten zum Finden von Kontakten im Kontaktdatenanbieter gezeigt.

Kontakte anhand eines bestimmten Datentyps abgleichen

Mit dieser Methode können Sie den Datentyp angeben, der abgeglichen werden soll. 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 Daten übereinstimmen, die in einer Postleitzahlzeile gespeichert sind.

Um diese Art der Abfrage zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie in den vorherigen Abschnitten aufgeführt:

  • Leseberechtigung für den Anbieter anfordern
  • 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.
  • Ausgewählten Kontakt-Listener festlegen.
  • Konstanten für die Cursorspaltenindexe definieren

    Auch wenn 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 den Lader.
  • Implementieren Sie „onLoadFinished()“ und „onLoaderReset()“.

In den folgenden Schritten wird der zusätzliche Code gezeigt, der erforderlich ist, um einen Suchstring mit einem bestimmten Detaildatentyp abzugleichen und die Ergebnisse anzuzeigen.

Datentyp und Tabelle auswählen

Wenn Sie nach einem bestimmten Detaildatentyp suchen möchten, müssen Sie den benutzerdefinierten MIME-Typ-Wert für den Datentyp kennen. 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 wird. Die Unterklassen haben Namen, die ihren Datentyp angeben. 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 die Tabelle ContactsContract.Data für Ihre Suche. Alle Konstanten, die Sie für die Projektion, Auswahlklausel und Sortierreihenfolge benötigen, werden in dieser Tabelle definiert oder von ihr übernommen.

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. Der Contacts Provider führt einen impliziten Join zwischen ContactsContract.Data und anderen Tabellen durch, bevor Zeilen zurückgegeben werden. 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 in einem bestimmten Datentyp nach einem String suchen möchten, erstellen Sie eine Auswahlklausel aus den folgenden Elementen:

  • Der Name der Spalte, die Ihre Suchzeichenfolge enthält. Dieser Name variiert je nach Datentyp. Daher müssen Sie die abgeleitete Klasse von ContactsContract.CommonDataKinds ermitteln, die dem Datentyp entspricht, und dann den Spaltennamen aus dieser abgeleiteten Klasse auswählen. Wenn Sie beispielsweise nach E-Mail-Adressen suchen möchten, verwenden Sie die Spalte Email.ADDRESS.
  • Der Suchstring selbst, der in der Auswahlklausel durch das Zeichen „?“ dargestellt wird.
  • 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 Unterklasse ContactsContract.CommonDataKinds. Der MIME-Typ-Wert für E-Mail-Daten ist beispielsweise Email.CONTENT_ITEM_TYPE. Setzen Sie den Wert in Anführungszeichen, indem Sie das Zeichen „'“ (einfaches Anführungszeichen) an den Anfang und das Ende der Konstante anhängen. 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(). Geben Sie von dieser Methode ein neues CursorLoader zurück, wobei die Projektion, der Auswahltextausdruck und das Auswahlarray als Argumente verwendet werden. 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 basierend auf einem bestimmten Detaildatentyp. Diese Methode eignet sich am besten, wenn der Schwerpunkt Ihrer App auf einen bestimmten Datentyp wie E-Mails liegt und Sie es Nutzern ermöglichen möchten, die mit einem Datenelement verknüpften Namen zu sehen.

Kontakte anhand beliebiger Datentypen abgleichen

Wenn Sie einen Kontakt anhand eines beliebigen Datentyps abrufen, werden Kontakte zurückgegeben, deren Daten mit dem Suchstring übereinstimmen, z. B. Name, E-Mail-Adresse, Postanschrift oder Telefonnummer. Das führt zu einer großen Anzahl von Suchergebnissen. Wenn der Suchstring beispielsweise „Mustermann“ ist, werden bei der Suche nach einem beliebigen Datentyp der Kontakt „Max Muster“ zurückgegeben. Es werden auch Kontakte zurückgegeben, die in der „Musterstraße“ wohnen.

Um diese Art der Abfrage zu implementieren, müssen Sie zuerst den folgenden Code implementieren, wie in den vorherigen Abschnitten aufgeführt:

  • Leseberechtigung für den Anbieter anfordern
  • 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.
  • Konstanten für die Cursorspaltenindexe definieren

    Für diese Art der Abfrage verwenden Sie dieselbe Tabelle wie im Abschnitt Kontakte nach Namen abgleichen und Ergebnisse auflisten. Verwenden Sie auch dieselben Spaltenindexe.

  • Definieren Sie die Methode „onItemClick()“.
  • Initialisieren Sie den Lader.
  • 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. Sie werden bei dieser Art des Abrufs nicht verwendet.

onCreateLoader() implementieren

Implementieren Sie die Methode onCreateLoader(), die eine neue CursorLoader zurückgibt. Sie müssen den Suchstring nicht in ein Muster konvertieren, da dies der Kontaktdatenanbieter automatisch erledigt. Verwenden Sie Contacts.CONTENT_FILTER_URI als Basis-URI und hängen Sie Ihren Suchstring an, indem Sie Uri.withAppendedPath() aufrufen. Die Verwendung dieses URI 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 Kontaktanbieter durchführt. Diese Methode eignet sich für Apps, in denen Funktionen ähnlich wie auf dem Kontaktlistenbildschirm der Kontakte-App implementiert werden sollen.