In dieser Lektion erfahren Sie, wie Sie Detaildaten für einen Kontakt abrufen, z. B. E-Mail-Adressen und Telefonnummern. Es sind die Details, nach denen Nutzer suchen, wenn sie einen Kontakt abrufen. Sie können alle Details für einen Kontakt angeben oder nur Details eines bestimmten Typs anzeigen lassen, z. B. E-Mail-Adressen.
Bei den Schritten in dieser Lektion wird davon ausgegangen,
ContactsContract.Contacts
Zeile für einen Kontakt, den der Nutzer ausgewählt hat.
In der Lektion Kontaktnamen abrufen erfahren Sie, wie Sie
um eine Liste von Kontakten abzurufen.
Alle Details zu einem Kontakt abrufen
Wenn Sie alle Details zu einem Kontakt abrufen möchten, suchen Sie in der Tabelle ContactsContract.Data
nach Zeilen, die die LOOKUP_KEY
des Kontakts enthalten. Diese Spalte ist in der Tabelle ContactsContract.Data
verfügbar, da der Kontaktdatenanbieter einen impliziten Join zwischen der Tabelle ContactsContract.Contacts
und der Tabelle ContactsContract.Data
vornimmt. Die
Die Spalte „LOOKUP_KEY
“ wird beschrieben
erhalten Sie in der Lektion Kontaktnamen abrufen.
Hinweis: Wenn alle Details für einen Kontakt abgerufen werden, sinkt die Leistung des Geräts, da alle Spalten in der Tabelle ContactsContract.Data
abgerufen werden müssen. Berücksichtigen Sie die Auswirkungen auf die Leistung,
verwenden Sie diese Technik.
Berechtigungen anfordern
Damit Ihre App Daten vom Contacts Provider abrufen kann, muss Ihre App
Berechtigung „READ_CONTACTS
“.
Fügen Sie das folgende untergeordnete Element von hinzu, um diese Berechtigung anzufordern
<manifest>
zu Ihrer Manifestdatei hinzu:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Projektion einrichten
Je nach Datentyp einer Zeile werden möglicherweise nur wenige oder viele Spalten verwendet. Außerdem
befinden sich die Daten je nach Datentyp
in verschiedenen Spalten.
Damit Sie alle möglichen Spalten für alle möglichen Datentypen erhalten, müssen Sie alle Spalten
Spaltennamen in die Projektion ein. Rufen Sie immer Data._ID
ab, wenn Sie das Ergebnis Cursor
an eine ListView
binden. Andernfalls funktioniert die Bindung nicht. Rufen Sie auch Data.MIMETYPE
ab, damit Sie den Datentyp jeder abgerufenen Zeile ermitteln können. Beispiel:
Kotlin
private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 )
Java
private static final String[] PROJECTION = { ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 };
Diese Projektion ruft alle Spalten für eine Zeile im
ContactsContract.Data
-Tabelle mit den hier definierten Spaltennamen
die Klasse ContactsContract.Data
.
Optional können Sie auch andere Spaltenkonstanten verwenden, die in der Klasse ContactsContract.Data
definiert oder von ihr übernommen wurden. Die Spalten SYNC1
bis SYNC4
sind jedoch für Synchronisierungsadapter vorgesehen und ihre Daten sind daher nicht nützlich.
Auswahlkriterien definieren
Definieren Sie eine Konstante für die Auswahlklausel, ein Array für Auswahlargumente und eine Variable für den Auswahlwert. Verwenden Sie
der Spalte Contacts.LOOKUP_KEY
, um
finden Sie den Kontakt. Beispiel:
Kotlin
// Defines the selection clause private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("") /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private var lookupKey: String? = null
Java
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" }; /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private lateinit var lookupKey: String
Sie verwenden "?" als Platzhalter in Ihrem Auswahltextausdruck verwenden, wird die resultierende Suche wird durch Bindung und nicht durch SQL-Kompilierung generiert. Bei diesem Ansatz eliminiert eine mögliche schädliche SQL-Injection.
Sortierreihenfolge festlegen
Legen Sie die gewünschte Sortierreihenfolge für die resultierende Cursor
fest. Bis
alle Zeilen für einen bestimmten Datentyp zusammen halten, sortieren nach
Data.MIMETYPE
Dieses Abfrageargument
gruppiert alle E-Mail-Zeilen, alle Telefonzeilen zusammen usw. Beispiel:
Kotlin
/* * Defines a string that specifies a sort order of MIME type */ private const val SORT_ORDER = ContactsContract.Data.MIMETYPE
Java
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;
Hinweis: Für einige Datentypen wird kein Untertyp verwendet. Sie können also nicht nach Untertyp sortieren.
Stattdessen müssen Sie die zurückgegebenen Cursor
durchgehen, den Datentyp der aktuellen Zeile ermitteln und Daten für Zeilen speichern, die einen Untertyp verwenden. Wann?
Nachdem Sie den Cursor gelesen haben, können Sie jeden Datentyp nach Untertyp sortieren und
Ergebnisse.
Loader initialisieren
E-Mails immer vom Contacts Provider (und allen anderen Contentanbietern) in einem
im Hintergrund. Verwenden Sie das Loader-Framework, das vom
LoaderManager
-Klasse und die
LoaderManager.LoaderCallbacks
-Oberfläche im Hintergrund
Abrufe.
Wenn Sie die Zeilen abrufen möchten, initialisieren Sie das Lade-Framework, indem Sie initLoader()
aufrufen. Übergeben Sie der Methode eine Ganzzahl-ID. Diese ID wird an LoaderManager.LoaderCallbacks
-Methoden übergeben. Mit der Kennung können Sie mehrere Loader in einer App verwenden, da Sie sie voneinander unterscheiden können.
Das folgende Snippet zeigt, wie das Loader-Framework initialisiert wird:
Kotlin
// Defines a constant that identifies the loader private const val DETAILS_QUERY_ID: Int = 0 class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Initializes the loader framework loaderManager.initLoader(DETAILS_QUERY_ID, null, this)
Java
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Defines a constant that identifies the loader static int DETAILS_QUERY_ID = 0; ... @Override public void onCreate(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
onCreateLoader() implementieren
Implementieren Sie die Methode onCreateLoader()
, die direkt nach dem Aufruf vom Loader-Framework aufgerufen wird.
initLoader()
. Diese Methode gibt eine CursorLoader
zurück. Da Sie in der Tabelle ContactsContract.Data
suchen, verwenden Sie die Konstante Data.CONTENT_URI
als Inhalts-URI.
Beispiel:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { // Choose the proper action mLoader = when(loaderId) { DETAILS_QUERY_ID -> { // Assigns the selection parameter selectionArgs[0] = lookupKey // Starts the query activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } } ... } return mLoader }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter selectionArgs[0] = lookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ); }
onLoadFinished() und onLoaderReset() implementieren
Implementieren Sie die
onLoadFinished()
. Das Lade-Framework ruft onLoadFinished()
auf, wenn der Kontaktdatenanbieter die Ergebnisse der Abfrage zurückgibt. Beispiel:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { when(loader.id) { DETAILS_QUERY_ID -> { /* * Process the resulting Cursor here. */ } ... } }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * Process the resulting Cursor here. */ } break; ... } }
Die Methode onLoaderReset()
wird aufgerufen, wenn das Lade-Framework erkennt, dass sich die Daten geändert haben, die dem Ergebnis Cursor
zugrunde liegen. Entferne an dieser Stelle alle vorhandenen Referenzen
zu Cursor
hinzu, indem Sie sie auf null setzen. Andernfalls wird die alte Cursor
vom Loader-Framework nicht zerstört und es kommt zu einem Speicherleck. Beispiel:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { when (loader.id) { DETAILS_QUERY_ID -> { /* * If you have current references to the Cursor, * remove them here. */ } ... } }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * If you have current references to the Cursor, * remove them here. */ } break; }
Bestimmte Details zu einem Kontakt abrufen
Das Abrufen eines bestimmten Datentyps für einen Kontakt, z. B. alle E-Mails, folgt demselben Muster dass alle Details abgerufen werden. Das sind die einzigen Änderungen, die Sie am Code vornehmen müssen, der unter Alle Details für einen Kontakt abrufen aufgeführt ist:
- Projektion
-
Ändern Sie die Projektion so, dass nur die Spalten abgerufen werden, die für den
Datentyp. Ändern Sie auch die Projektion so, dass die Spaltennamen-Konstanten verwendet werden, die in der
ContactsContract.CommonDataKinds
-Unterklasse für Datentyp. - Auswahl
-
Ändern Sie den Auswahltext, um nach dem
MIMETYPE
-Wert zu suchen, der für Ihren Datentyp spezifisch ist. - Sortierreihenfolge
-
Da Sie nur einen einzigen Detailtyp auswählen, gruppieren Sie die zurückgegebenen
Cursor
nicht nachData.MIMETYPE
.
Diese Änderungen werden in den folgenden Abschnitten beschrieben.
Projektion definieren
Definieren Sie die Spalten, die Sie abrufen möchten, indem Sie die Spaltennamenkonstanten in der Unterklasse von ContactsContract.CommonDataKinds
für den Datentyp verwenden.
Wenn Sie Ihre Cursor
an eine ListView
binden möchten, müssen Sie die Spalte _ID
abrufen. Wenn Sie beispielsweise E-Mail-Daten abrufen möchten, definieren Sie die folgende Projektion:
Kotlin
private val PROJECTION: Array<String> = arrayOf( ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL )
Java
private static final String[] PROJECTION = { ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL };
Beachten Sie, dass diese Projektion die in der Klasse definierten Spaltennamen verwendet.
ContactsContract.CommonDataKinds.Email
anstelle der Spaltennamen
definiert in der Klasse ContactsContract.Data
. Mit der E-Mail-spezifischen
Spaltennamen, die den Code lesbarer machen.
In der Projektion können Sie auch eine der anderen Spalten verwenden, die in der ContactsContract.CommonDataKinds
-Unterklasse definiert sind.
Auswahlkriterien definieren
Definieren Sie einen Suchtextausdruck, mit dem Zeilen für einen bestimmten Kontakt abgerufen werden
LOOKUP_KEY
und die
Data.MIMETYPE
der Details, die Sie
Setzen Sie den Wert MIMETYPE
in
einfache Anführungszeichen durch Verkettung eines "'
" (einfaches Anführungszeichen) bis zum Anfang und Ende
der Konstante; Andernfalls interpretiert der Anbieter die Konstante als Variablennamen
als Stringwert. Für diesen Wert müssen Sie keinen Platzhalter verwenden,
statt eines vom Nutzer bereitgestellten Werts. Beispiel:
Kotlin
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private const val SELECTION = "${ContactsContract.Data.LOOKUP_KEY} = ? AND " + "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("")
Java
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private static final String SELECTION = Data.LOOKUP_KEY + " = ?" + " AND " + Data.MIMETYPE + " = " + "'" + Email.CONTENT_ITEM_TYPE + "'"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" };
Sortierreihenfolge definieren
Definieren Sie eine Sortierfolge für die zurückgegebenen Cursor
. Da Sie gerade eine
Datentyp angegeben haben, lassen Sie die Sortierung für MIMETYPE
weg.
Wenn der gesuchte Detailtyp einen Untertyp umfasst, sortieren Sie ihn stattdessen.
Bei E-Mail-Daten können Sie beispielsweise nach den folgenden Email.TYPE
sortieren:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";