Contentanbieter – Grundlagen

Ein Contentanbieter verwaltet den Zugriff auf ein zentrales Repository mit Daten. Ein Anbieter ist Teil einer Android-App, die oft eine eigene Benutzeroberfläche für die Arbeit mit mit den Daten. Contentanbieter werden jedoch hauptsächlich von anderen Anwendungen, die über ein Anbieter-Clientobjekt auf den Anbieter zugreifen. Gemeinsam können Anbieter und Provider-Kunden bieten eine einheitliche, standardisierte Schnittstelle für Daten, die auch die Kommunikation zwischen Prozessen und den sicheren Datenzugriff.

Normalerweise arbeiten Sie mit Contentanbietern in einem von zwei Szenarien zusammen: Implementierung um auf einen vorhandenen Contentanbieter in einer anderen Anwendung zuzugreifen, einen neuen Contentanbieter in Ihrer Anwendung verwenden, um Daten mit anderen Anwendungen zu teilen.

Diese Seite deckt die Grundlagen der Zusammenarbeit mit bestehenden Contentanbietern ab. Um mehr über die Implementierung Contentanbieter in Ihren eigenen Anwendungen <ph type="x-smartling-placeholder"></ph> Contentanbieter erstellen

In diesem Thema wird Folgendes beschrieben:

  • Funktionsweise von Contentanbietern
  • Die API, die Sie zum Abrufen von Daten von einem Contentanbieter verwenden.
  • Die API, die Sie zum Einfügen, Aktualisieren oder Löschen von Daten bei einem Contentanbieter verwenden.
  • Weitere API-Funktionen, die die Zusammenarbeit mit Anbietern erleichtern.

Übersicht

Ein Contentanbieter präsentiert Daten für externe Anwendungen als eine oder mehrere Tabellen, die ähnlich den Tabellen in einer relationalen Datenbank. Eine Zeile steht für eine Instanz eines Typs. Daten erfasst, die der Anbieter erfasst, und jede Spalte in der Zeile steht für ein einzelnes für eine Instanz erfasste Daten.

Ein Contentanbieter koordiniert den Zugriff auf die Datenspeicherebene in Ihrer Anwendung für eine APIs und Komponenten zu erstellen. Wie in Abbildung 1 dargestellt, umfassen diese Folgendes:

  • Anderen Anwendungen Zugriff auf Ihre Anwendungsdaten gewähren
  • Daten an ein Widget senden
  • Über die Suche benutzerdefinierte Suchvorschläge für Ihre Anwendung zurückgeben Framework mit SearchRecentSuggestionsProvider
  • Synchronisieren von Anwendungsdaten mit Ihrem Server mithilfe einer Implementierung von AbstractThreadedSyncAdapter
  • Laden von Daten in Ihre UI mit einem CursorLoader
Beziehung zwischen Contentanbieter und anderen Komponenten.

Abbildung 1: Beziehung zwischen einem Contentanbieter und anderen Komponenten.

Auf einen Anbieter zugreifen

Wenn Sie auf Daten bei einem Contentanbieter zugreifen möchten, verwenden Sie die Methode ContentResolver-Objekt im Context, um mit dem Anbieter als Kunde zu kommunizieren. Die Das ContentResolver-Objekt kommuniziert mit dem Anbieterobjekt, einem Instanz einer Klasse, die ContentProvider implementiert.

Anbieter -Objekt Datenanforderungen von Clients empfängt, die angeforderte Aktion durchführt und den Fehlerwert Ergebnisse. Dieses Objekt verfügt über Methoden, die identisch benannte Methoden im Anbieterobjekt aufrufen, Eine Instanz einer der konkreten abgeleiteten Klassen von ContentProvider. Die ContentResolver-Methoden stellen die grundlegenden „CRUD“ (Erstellen, Abrufen, Aktualisieren und Löschen) des nichtflüchtigen Speichers.

Ein häufiges Muster für den Zugriff auf ein ContentProvider über Ihre Benutzeroberfläche verwendet einen Mit CursorLoader können Sie eine asynchrone Abfrage im Hintergrund ausführen. Die Activity oder Fragment in Ihrer UI ruft ein CursorLoader hinzu, die wiederum den Wert ContentProvider mit ContentResolver.

So bleibt die Benutzeroberfläche für den Nutzer verfügbar, während die Abfrage ausgeführt wird. Dieses die Interaktion verschiedener Objekte und die zugrunde liegende Speichermechanismus, wie in Abbildung 2 dargestellt.

Interaktion zwischen ContentProvider, anderen Klassen und Speicher.

Abbildung 2: Interaktion zwischen ContentProvider, anderen Klassen und Speicher.

Hinweis:Für den Zugriff auf einen Anbieter muss Ihre Anwendung in der Regel bestimmte Berechtigungen in der Manifest-Datei. Dieses Entwicklungsmuster wird ausführlicher in der Berechtigungen für Contentanbieter.

Einer der integrierten Anbieter der Android-Plattform ist der User Dictionary Provider, nicht standardmäßige Wörter speichert, die die Nutzenden behalten möchten. Tabelle 1 zeigt, könnten die Daten in der Tabelle dieses Anbieters aussehen:

Tabelle 1:Beispieltabelle für „Mein Wörterbuch“.

Wortspiele App-ID Beiträgen Sprache _ID
mapreduce Nutzer1 100 de_DE 1
precompiler Nutzer 14 200 fr_FR 2
applet Nutzer 2 225 fr_CA 3
const Nutzer1 255 pt_BR 4
int Nutzer 5 100 de_DE 5

In Tabelle 1 steht jede Zeile für ein Wort, das nicht Standardwörterbuch gefunden. Jede Spalte repräsentiert ein Datenelement für dieses Wort, z. B. die Sprache, in der es zum ersten Mal aufgetreten ist. Die Spaltenüberschriften sind Spaltennamen, die in und den Anbieter. Um beispielsweise auf die Sprache einer Zeile zu verweisen, verweisen Sie auf die entsprechende Spalte locale. Für bei diesem Anbieter dient die Spalte _ID als Primärschlüsselspalte, die automatisch verwaltet werden.

Um eine Liste der Wörter und ihrer Sprachen vom User Dictionary Provider zu erhalten, rufst du ContentResolver.query() an. Die Methode query() ruft die Methode ContentProvider.query()-Methode definiert durch das Mein Wörterbuch. Die folgenden Codezeilen zeigen eine ContentResolver.query()-Anruf:

Kotlin

// Queries the UserDictionary and returns results
cursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
        projection,                        // The columns to return for each row
        selectionClause,                   // Selection criteria
        selectionArgs.toTypedArray(),      // Selection criteria
        sortOrder                          // The sort order for the returned rows
)

Java

// Queries the UserDictionary and returns results
cursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    projection,                        // The columns to return for each row
    selectionClause,                   // Selection criteria
    selectionArgs,                     // Selection criteria
    sortOrder);                        // The sort order for the returned rows

Tabelle 2 zeigt, wie die Argumente query(Uri,projection,selection,selectionArgs,sortOrder) stimmt mit einer SQL-SELECT-Anweisung überein:

Tabelle 2:query() im Vergleich zur SQL-Abfrage.

query() Argument SELECT Keyword/Parameter Hinweise
Uri FROM table_name Uri ist der Tabelle im Anbieter table_name zugeordnet.
projection col,col,col,... projection ist ein Array von Spalten, das in jeder Zeile enthalten ist. abgerufen werden.
selection WHERE col = value selection gibt die Kriterien für die Auswahl von Zeilen an.
selectionArgs Kein genaues Äquivalent. Auswahlargumente ersetzen ?-Platzhalter in der Auswahlklausel.
sortOrder ORDER BY col,col,... sortOrder gibt die Reihenfolge an, in der Zeilen im zurückgegebenen Cursor.

Inhalts-URIs

Ein Inhalts-URI ist ein URI, der Daten bei einem Anbieter identifiziert. Inhalts-URIs den symbolischen Namen des gesamten Anbieters – seiner Zertifizierungsstelle – und einen der auf eine Tabelle verweist, also einen Pfad. Wenn du anrufst Clientmethode für den Zugriff auf eine Tabelle bei einem Anbieter, ist der Inhalts-URI für die Tabelle einer der folgenden Werte: die Argumente.

In den vorhergehenden Codezeilen wird die Konstante CONTENT_URI enthält den Inhalts-URI von Die Tabelle Words des Nutzerwörterbuchanbieters. Das ContentResolver parst die Autorität des URI und verwendet sie, um den Anbieter aufzulösen. Vergleich der Befugnisse mit einer Systemtabelle bekannter Anbieter. Die ContentResolver kann dann die Abfrageargumente an die richtige Dienstanbieter.

Bei ContentProvider wird anhand des Pfadteils des Inhalts-URI der um darauf zuzugreifen. Ein Anbieter verfügt in der Regel über einen Pfad für jede bereitgestellte Tabelle.

In den vorherigen Codezeilen lautet der vollständige URI für die Tabelle Words:

content://user_dictionary/words
  • Der String content:// ist das Schema, das immer vorhanden ist. und identifiziert dies als Inhalts-URI.
  • Der String user_dictionary ist die Befugnis des Anbieters.
  • Der String words ist der Pfad der Tabelle.

Bei vielen Anbietern können Sie auf eine einzelne Zeile in einer Tabelle zugreifen, indem Sie einen ID-Wert anhängen. am Ende des URI ein. Um beispielsweise eine Zeile abzurufen, deren _ID gleich 4 vom User Dictionary Provider, können Sie diesen Inhalts-URI verwenden:

Kotlin

val singleUri: Uri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4)

Java

Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

Sie verwenden häufig ID-Werte, wenn Sie eine Reihe von Zeilen abrufen und dann aktualisieren oder löschen möchten eine davon.

Hinweis:Die Klassen Uri und Uri.Builder Praktische Methoden zur Konstruktion wohlgeformter URI-Objekte aus Strings enthalten. Die Die Klasse ContentUris enthält praktische Methoden zum Anhängen von ID-Werten an URI. Im vorherigen Snippet wird withAppendedId() verwendet, um eine ID an den Inhalts-URI des User Dictionary-Anbieters anzuhängen.

Daten vom Anbieter abrufen

In diesem Abschnitt wird beschrieben, wie Sie mithilfe des User Dictionary Providers Daten von einem Anbieter abrufen können. als Beispiel.

Der Einfachheit halber rufen die Code-Snippets in diesem Abschnitt ContentResolver.query() für den UI-Thread. In tatsächlicher Code hingegen asynchron in einem separaten Thread. Sie können verwenden Sie die Klasse CursorLoader, die im in den Anleitung zu Ladeprogrammen. Außerdem handelt es sich bei den Codezeilen nur um Snippets. Es wird kein vollständiges .

So rufen Sie Daten von einem Anbieter ab:

  1. Fordern Sie Lesezugriff für den Anbieter an.
  2. Definieren Sie den Code, der eine Abfrage an den Anbieter sendet.

Lesezugriff auf Berechtigung anfordern

Zum Abrufen von Daten von einem Anbieter benötigt Ihre Anwendung Lesezugriff für den Dienstanbieter. Sie können diese Berechtigung nicht zur Laufzeit anfordern. Stattdessen müssen Sie angeben, benötigen Sie diese Berechtigung in Ihrem Manifest. Verwenden Sie dazu den <uses-permission> und den genauen Berechtigungsnamen, der vom Dienstanbieter.

Wenn Sie dieses Element in Ihrem Manifest angeben, fordern Sie Folgendes an: Berechtigung für Ihre Anwendung. Wenn Nutzer Ihre Anwendung installieren, gewähren sie implizit für diese Anfrage.

Wie Sie den genauen Namen der Leseberechtigung für den verwendeten Anbieter finden, Namen anderer Zugriffsberechtigungen, die der Anbieter verwendet, finden Sie in der Dokumentation.

Die Rolle der Berechtigungen beim Zugriff auf Anbieter wird ausführlicher in der Berechtigungen für Contentanbieter.

Der User Dictionary Provider definiert die Berechtigung. android.permission.READ_USER_DICTIONARY in seiner Manifest-Datei, sodass ein Anwendung, die Daten vom Anbieter lesen möchte, muss diese Berechtigung anfordern.

Abfrage erstellen

Der nächste Schritt beim Abrufen von Daten von einem Anbieter besteht darin, eine Abfrage zu erstellen. Das folgende Snippet definiert einige Variablen für den Zugriff auf den Nutzerwörterbuchanbieter:

Kotlin

// A "projection" defines the columns that are returned for each row
private val mProjection: Array<String> = arrayOf(
        UserDictionary.Words._ID,    // Contract class constant for the _ID column name
        UserDictionary.Words.WORD,   // Contract class constant for the word column name
        UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
)

// Defines a string to contain the selection clause
private var selectionClause: String? = null

// Declares an array to contain selection arguments
private lateinit var selectionArgs: Array<String>

Java

// A "projection" defines the columns that are returned for each row
String[] mProjection =
{
    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
    UserDictionary.Words.WORD,   // Contract class constant for the word column name
    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
};

// Defines a string to contain the selection clause
String selectionClause = null;

// Initializes an array to contain selection arguments
String[] selectionArgs = {""};

Im nächsten Snippet sehen Sie, ContentResolver.query(), mithilfe des Nutzerwörterbuchs Anbieter als Beispiel. Eine Anbieter-Client-Abfrage ähnelt einer SQL-Abfrage und enthält eine Satz von Spalten, die zurückgegeben werden sollen, ein Satz von Auswahlkriterien und eine Sortierreihenfolge.

Die von der Abfrage zurückgegebene Gruppe von Spalten wird als Projektion bezeichnet. ist die Variable mProjection.

Der Ausdruck, der die abzurufenden Zeilen angibt, wird in eine Auswahlklausel aufgeteilt und Auswahlargumente. Die Auswahlklausel ist eine Kombination aus logischen und booleschen Ausdrücken, Spaltennamen und -werten. Die Variable lautet mSelectionClause. Wenn Sie den Parameter austauschbarer Parameter ? anstelle eines Werts verwendet, ruft die Abfragemethode den Wert aus dem Array der Auswahlargumente, d. h. der Variable mSelectionArgs.

Wenn im nächsten Snippet der Nutzer kein Wort eingibt, wird die Auswahlklausel auf null und die Abfrage gibt alle Wörter im Anbieter zurück. Wenn der Nutzer Wort enthalten, wird die Auswahlklausel auf UserDictionary.Words.WORD + " = ?" gesetzt und wird das erste Element des Arrays der Auswahlargumente auf das vom Nutzer eingegebene Wort gesetzt.

Kotlin

/*
 * This declares a String array to contain the selection arguments.
 */
private lateinit var selectionArgs: Array<String>

// Gets a word from the UI
searchString = searchWord.text.toString()

// Insert code here to check for invalid or malicious input

// If the word is the empty string, gets everything
selectionArgs = searchString?.takeIf { it.isNotEmpty() }?.let {
    selectionClause = "${UserDictionary.Words.WORD} = ?"
    arrayOf(it)
} ?: run {
    selectionClause = null
    emptyArray<String>()
}

// Does a query against the table and returns a Cursor object
mCursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI, // The content URI of the words table
        projection,                       // The columns to return for each row
        selectionClause,                  // Either null or the word the user entered
        selectionArgs,                    // Either empty or the string the user entered
        sortOrder                         // The sort order for the returned rows
)

// Some providers return null if an error occurs, others throw an exception
when (mCursor?.count) {
    null -> {
        /*
         * Insert code here to handle the error. Be sure not to use the cursor!
         * You might want to call android.util.Log.e() to log this error.
         */
    }
    0 -> {
        /*
         * Insert code here to notify the user that the search is unsuccessful. This isn't
         * necessarily an error. You might want to offer the user the option to insert a new
         * row, or re-type the search term.
         */
    }
    else -> {
        // Insert code here to do something with the results
    }
}

Java

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] selectionArgs = {""};

// Gets a word from the UI
searchString = searchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(searchString)) {
    // Setting the selection clause to null returns all words
    selectionClause = null;
    selectionArgs[0] = "";

} else {
    // Constructs a selection clause that matches the word that the user entered
    selectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments
    selectionArgs[0] = searchString;

}

// Does a query against the table and returns a Cursor object
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI, // The content URI of the words table
    projection,                       // The columns to return for each row
    selectionClause,                  // Either null or the word the user entered
    selectionArgs,                    // Either empty or the string the user entered
    sortOrder);                       // The sort order for the returned rows

// Some providers return null if an error occurs, others throw an exception
if (null == mCursor) {
    /*
     * Insert code here to handle the error. Be sure not to use the cursor! You can
     * call android.util.Log.e() to log this error.
     *
     */
// If the Cursor is empty, the provider found no matches
} else if (mCursor.getCount() < 1) {

    /*
     * Insert code here to notify the user that the search is unsuccessful. This isn't necessarily
     * an error. You can offer the user the option to insert a new row, or re-type the
     * search term.
     */

} else {
    // Insert code here to do something with the results

}

Diese Abfrage entspricht der folgenden SQL-Anweisung:

SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC;

In dieser SQL-Anweisung werden die tatsächlichen Spaltennamen anstelle der Vertragsklassenkonstanten verwendet.

Schutz vor schädlichen Eingaben

Wenn sich die vom Contentanbieter verwalteten Daten in einer SQL-Datenbank befinden, einschließlich externer, nicht vertrauenswürdiger Daten Daten in SQL-Rohanweisungen einschleusen.

Sehen Sie sich die folgende Auswahlklausel an:

Kotlin

// Constructs a selection clause by concatenating the user's input to the column name
var selectionClause = "var = $mUserInput"

Java

// Constructs a selection clause by concatenating the user's input to the column name
String selectionClause = "var = " + userInput;

Wenn Sie dies tun, kann der Nutzer möglicherweise schädlichen SQL-Code mit Ihrer SQL-Anweisung verketten. Nutzende können beispielsweise „nothing; DROP TABLE *;" für mUserInput, die führt zur Auswahlklausel var = nothing; DROP TABLE *;.

Da die als SQL-Anweisung behandelt wird, löscht der Anbieter möglicherweise alle Tabellen in der zugrunde liegenden SQLite-Datenbank, es sei denn, der Anbieter ist so eingerichtet, SQL-Einschleusungsversuche

Um dieses Problem zu vermeiden, sollten Sie eine Auswahlklausel verwenden, die ? als austauschbares Objekt verwendet. und einem separaten Array von Auswahlargumenten. Auf diese Weise können die direkt an die Abfrage gebunden ist, anstatt als Teil einer SQL-Anweisung interpretiert zu werden. Da sie nicht als SQL behandelt wird, kann die Nutzereingabe kein schädliches SQL einschleusen. Anstelle von verwenden Sie diese Auswahlklausel:

Kotlin

// Constructs a selection clause with a replaceable parameter
var selectionClause = "var = ?"

Java

// Constructs a selection clause with a replaceable parameter
String selectionClause =  "var = ?";

Richten Sie das Array von Auswahlargumenten so ein:

Kotlin

// Defines a mutable list to contain the selection arguments
var selectionArgs: MutableList<String> = mutableListOf()

Java

// Defines an array to contain the selection arguments
String[] selectionArgs = {""};

Geben Sie einen Wert in das Array der Auswahlargumente ein:

Kotlin

// Adds the user's input to the selection argument
selectionArgs += userInput

Java

// Sets the selection argument to the user's input
selectionArgs[0] = userInput;

Eine Auswahlklausel, die ? als austauschbaren Parameter verwendet, und ein Array von Das Array der Auswahlargumente ist die bevorzugte Methode, um eine Auswahl anzugeben, auch wenn der Anbieter nicht basierend auf einer SQL-Datenbank.

Abfrageergebnisse anzeigen

Die Clientmethode ContentResolver.query() immer gibt ein Cursor zurück, das die durch die Abfrage Projektion für die Zeilen, die den Auswahlkriterien der Abfrage entsprechen. A Das Objekt Cursor bietet zufälligen Lesezugriff auf die Zeilen und Spalten, die es enthält enthält.

Mit den Methoden Cursor können Sie über die Zeilen im den Datentyp jeder Spalte bestimmen, die Daten aus einer Spalte abrufen und Eigenschaften der Ergebnisse.

Einige Cursor-Implementierungen werden automatisch Objekt aktualisieren, wenn sich die Daten des Anbieters ändern, Methoden in einem Beobachterobjekt auslösen wenn sich Cursor ändert, oder beides.

Hinweis:Ein Anbieter kann den Zugriff auf Spalten basierend auf der Art des Objekt, das die Abfrage durchführt. Zum Beispiel schränkt der Contacts Provider den Zugriff für einige Spalten auf Synchronisierungsadapter verwenden, sodass sie nicht zu einer Aktivität oder einem Dienst zurückgeleitet werden.

Wenn keine Zeilen den Auswahlkriterien entsprechen, gibt ein Cursor-Objekt zurück, für das Cursor.getCount() ist 0, d. h. ein leerer Cursor.

Wenn ein interner Fehler auftritt, hängen die Ergebnisse der Abfrage vom jeweiligen Anbieter ab. Möglicherweise null zurückgeben oder eine Exception ausgeben.

Da es sich bei Cursor um eine Liste von Zeilen handelt, ist es sinnvoll, ist die Verknüpfung mit einem ListView-Cursor mit SimpleCursorAdapter.

Mit dem folgenden Snippet wird der Code des vorherigen Snippets fortgesetzt. Es wird ein SimpleCursorAdapter-Objekt, das Cursor enthält und legt dieses Objekt als Adapter für ein ListView

Kotlin

// Defines a list of columns to retrieve from the Cursor and load into an output row
val wordListColumns : Array<String> = arrayOf(
        UserDictionary.Words.WORD,      // Contract class constant containing the word column name
        UserDictionary.Words.LOCALE     // Contract class constant containing the locale column name
)

// Defines a list of View IDs that receive the Cursor columns for each row
val wordListItems = intArrayOf(R.id.dictWord, R.id.locale)

// Creates a new SimpleCursorAdapter
cursorAdapter = SimpleCursorAdapter(
        applicationContext,             // The application's Context object
        R.layout.wordlistrow,           // A layout in XML for one row in the ListView
        mCursor,                        // The result from the query
        wordListColumns,                // A string array of column names in the cursor
        wordListItems,                  // An integer array of view IDs in the row layout
        0                               // Flags (usually none are needed)
)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter)

Java

// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] wordListColumns =
{
    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
};

// Defines a list of View IDs that receive the Cursor columns for each row
int[] wordListItems = { R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter
cursorAdapter = new SimpleCursorAdapter(
    getApplicationContext(),               // The application's Context object
    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    mCursor,                               // The result from the query
    wordListColumns,                       // A string array of column names in the cursor
    wordListItems,                         // An integer array of view IDs in the row layout
    0);                                    // Flags (usually none are needed)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter);

Hinweis: Um ein ListView mit einem Cursor muss der Cursor eine Spalte mit dem Namen _ID enthalten. Aus diesem Grund ruft die zuvor gezeigte Abfrage die Spalte _ID für den Words angezeigt, auch wenn sie von ListView nicht angezeigt wird. Diese Einschränkung erklärt auch, warum die meisten Anbieter jeweils eine _ID-Spalte für jede der ihre Tabellen.

Daten aus Abfrageergebnissen abrufen

Sie können sie nicht nur für Abfrageergebnisse, sondern auch für andere Aufgaben verwenden. Für Sie können z. B. Schreibweisen vom User Dictionary Provider abrufen und sie dann in anderen Anbietern. Dazu iterieren Sie über die Zeilen in Cursor, wie im folgenden Beispiel gezeigt:

Kotlin

/*
* Only executes if the cursor is valid. The User Dictionary Provider returns null if
* an internal error occurs. Other providers might throw an Exception instead of returning null.
*/
mCursor?.apply {
    // Determine the column index of the column named "word"
    val index: Int = getColumnIndex(UserDictionary.Words.WORD)

    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you get an
     * exception.
     */
    while (moveToNext()) {
        // Gets the value from the column
        newWord = getString(index)

        // Insert code here to process the retrieved word
        ...
        // End of while loop
    }
}

Java

// Determine the column index of the column named "word"
int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);

/*
 * Only executes if the cursor is valid. The User Dictionary Provider returns null if
 * an internal error occurs. Other providers might throw an Exception instead of returning null.
 */

if (mCursor != null) {
    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you get an
     * exception.
     */
    while (mCursor.moveToNext()) {

        // Gets the value from the column
        newWord = mCursor.getString(index);

        // Insert code here to process the retrieved word
        ...
        // End of while loop
    }
} else {

    // Insert code here to report an error if the cursor is null or the provider threw an exception
}

Cursor-Implementierungen enthalten mehrere „get“-Elemente Methoden für das Abrufen verschiedener Datentypen aus dem Objekt. Das vorherige Snippet verwendet getString(). Sie haben auch eine getType()-Methode, die einen Wert zurückgibt, der angibt, den Datentyp der Spalte.

Ergebnisressourcen der Releaseabfrage

Cursor-Objekte müssen geschlossen werden, wenn sie nicht mehr benötigt werden, sodass mit ihnen verknüpfte Ressourcen freigegeben werden früher. Rufen Sie dazu entweder close() oder mithilfe von eine try-with-resources-Anweisung in der Programmiersprache Java oder die use() in der Programmiersprache Kotlin ab.

Berechtigungen für Contentanbieter

Die Anwendung eines Anbieters kann Berechtigungen festlegen, die andere Anwendungen benötigen, um auf die Daten des Anbieters zugreifen. Diese Berechtigungen teilen dem Nutzer mit, welche Daten auf die eine App zugreifen möchte. Je nach Anbieteranforderungen werden andere Anwendungen die Berechtigungen anfordern, die sie für den Zugriff auf den Anbieter benötigen. Endnutzer sehen die angeforderten wenn sie die App installieren.

Wenn die Anwendung eines Anbieters keine Berechtigungen festlegt, haben andere Anwendungen keine Zugriff auf die Daten des Anbieters, es sei denn, der Anbieter wird exportiert. Außerdem können Komponenten in der Anwendung des Anbieters immer vollständigen Lese- und Schreibzugriff haben, unabhängig von angegebenen Berechtigungen.

Der User Dictionary Provider benötigt die Berechtigung android.permission.READ_USER_DICTIONARY, Daten daraus abzurufen. Der Anbieter hat eine separate android.permission.WRITE_USER_DICTIONARY Berechtigung zum Einfügen, Aktualisieren oder Löschen von Daten.

Um die erforderlichen Berechtigungen für den Zugriff auf einen Anbieter zu erhalten, fordert eine Anwendung sie mit einem <uses-permission> -Element in seiner Manifest-Datei. Wenn der Android Package Manager die App installiert, muss alle Berechtigungen genehmigen, die von der Anwendung angefordert werden. Wenn der Nutzer sie genehmigt, Der Paketmanager setzt die Installation fort. Wenn der Nutzer sie nicht genehmigt, die Installation beendet.

Im folgenden Beispiel <uses-permission> -Element fordert Lesezugriff beim Nutzerwörterbuchanbieter an:

<uses-permission android:name="android.permission.READ_USER_DICTIONARY">

Die Auswirkungen von Berechtigungen auf den Anbieterzugriff werden unter Sicherheitstipps

Daten einfügen, aktualisieren und löschen

So wie Sie Daten von einem Anbieter abrufen, verwenden Sie auch die Interaktion zwischen einen Anbieterclient und die ContentProvider des Anbieters, um Daten zu ändern. Sie rufen eine Methode von ContentResolver mit Argumenten auf, die an die entsprechende Methode von ContentProvider. Anbieter und Anbieter für Sicherheit und Interprozesskommunikation.

Daten einfügen

Um Daten in einen Anbieter einzufügen, rufen Sie die Methode ContentResolver.insert() . Mit dieser Methode wird eine neue Zeile in den Anbieter eingefügt und ein Inhalts-URI für diese Zeile zurückgegeben. Das folgende Snippet zeigt, wie ein neues Wort in den User Dictionary Provider eingefügt wird:

Kotlin

// Defines a new Uri object that receives the result of the insertion
lateinit var newUri: Uri
...
// Defines an object to contain the new values to insert
val newValues = ContentValues().apply {
    /*
     * Sets the values of each column and inserts the word. The arguments to the "put"
     * method are "column name" and "value".
     */
    put(UserDictionary.Words.APP_ID, "example.user")
    put(UserDictionary.Words.LOCALE, "en_US")
    put(UserDictionary.Words.WORD, "insert")
    put(UserDictionary.Words.FREQUENCY, "100")

}

newUri = contentResolver.insert(
        UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
        newValues                           // The values to insert
)

Java

// Defines a new Uri object that receives the result of the insertion
Uri newUri;
...
// Defines an object to contain the new values to insert
ContentValues newValues = new ContentValues();

/*
 * Sets the values of each column and inserts the word. The arguments to the "put"
 * method are "column name" and "value".
 */
newValues.put(UserDictionary.Words.APP_ID, "example.user");
newValues.put(UserDictionary.Words.LOCALE, "en_US");
newValues.put(UserDictionary.Words.WORD, "insert");
newValues.put(UserDictionary.Words.FREQUENCY, "100");

newUri = getContentResolver().insert(
    UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
    newValues                           // The values to insert
);

Die Daten für die neue Zeile werden in ein einzelnes ContentValues-Objekt übertragen, ähnelt in Form einem Cursor mit einer Zeile. Für die Spalten in diesem Objekt ist der Wert denselben Datentyp haben und keinen Wert angeben möchten, können Sie eine Spalte an null mit ContentValues.putNull().

Im vorherigen Snippet wurde die Spalte _ID nicht hinzugefügt, da diese Spalte beibehalten wird automatisch. Der Anbieter weist jeder Zeile, die_ID hinzugefügt. Anbieter verwenden diesen Wert normalerweise als Primärschlüssel der Tabelle.

Der in newUri zurückgegebene Inhalts-URI identifiziert die neu hinzugefügte Zeile mit im folgenden Format:

content://user_dictionary/words/<id_value>

<id_value> ist der Inhalt von _ID für die neue Zeile. Die meisten Anbieter können diese Form von Inhalts-URI automatisch erkennen und dann den angeforderten für diese Zeile.

Um den Wert von _ID aus dem zurückgegebenen Uri zu erhalten, rufen Sie ContentUris.parseId()

Daten aktualisieren

Um eine Zeile zu aktualisieren, verwenden Sie ein ContentValues-Objekt mit dem aktualisierten Werte, genau wie bei Einfügungen und Auswahlkriterien wie bei einer Abfrage. Die Client-Methode, die Sie verwenden, ist ContentResolver.update() Sie müssen nur in das ContentValues-Objekt für die Spalten, die Sie aktualisieren. Wenn Sie den Inhalt einer Spalte löschen möchten, setzen Sie den Wert auf null.

Das folgende Snippet ändert alle Zeilen, deren Sprache die Sprache "en" hat, in haben die Sprache null. Der Rückgabewert ist die Anzahl der Zeilen, die aktualisiert wurden.

Kotlin

// Defines an object to contain the updated values
val updateValues = ContentValues().apply {
    /*
     * Sets the updated value and updates the selected words.
     */
    putNull(UserDictionary.Words.LOCALE)
}

// Defines selection criteria for the rows you want to update
val selectionClause: String = UserDictionary.Words.LOCALE + "LIKE ?"
val selectionArgs: Array<String> = arrayOf("en_%")

// Defines a variable to contain the number of updated rows
var rowsUpdated: Int = 0
...
rowsUpdated = contentResolver.update(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        updateValues,                      // The columns to update
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

Java

// Defines an object to contain the updated values
ContentValues updateValues = new ContentValues();

// Defines selection criteria for the rows you want to update
String selectionClause = UserDictionary.Words.LOCALE +  " LIKE ?";
String[] selectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows
int rowsUpdated = 0;
...
/*
 * Sets the updated value and updates the selected words.
 */
updateValues.putNull(UserDictionary.Words.LOCALE);

rowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    updateValues,                      // The columns to update
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

Nutzereingabe beim Anruf bereinigen ContentResolver.update() Weitere Informationen über lesen Sie den Abschnitt Schutz vor schädlichen Eingaben.

Daten löschen

Das Löschen von Zeilen ähnelt dem Abrufen von Zeilendaten. Sie legen Auswahlkriterien für die Zeilen fest. die Sie löschen möchten, und die Client-Methode gibt die Anzahl der gelöschten Zeilen zurück. Mit dem folgenden Snippet werden Zeilen gelöscht, deren App-ID mit "user" übereinstimmt. Die Methode gibt den Fehlerwert Anzahl der gelöschten Zeilen.

Kotlin

// Defines selection criteria for the rows you want to delete
val selectionClause = "${UserDictionary.Words.APP_ID} LIKE ?"
val selectionArgs: Array<String> = arrayOf("user")

// Defines a variable to contain the number of rows deleted
var rowsDeleted: Int = 0
...
// Deletes the words that match the selection criteria
rowsDeleted = contentResolver.delete(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

Java

// Defines selection criteria for the rows you want to delete
String selectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] selectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted
int rowsDeleted = 0;
...
// Deletes the words that match the selection criteria
rowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

Nutzereingabe beim Anruf bereinigen ContentResolver.delete() Weitere Informationen über lesen Sie den Abschnitt Schutz vor schädlichen Eingaben.

Datentypen des Anbieters

Contentanbieter können viele verschiedene Datentypen anbieten. Der User Dictionary Provider bietet nur Textanzeige. Anbieter können jedoch auch die folgenden Formate anbieten:

  • Ganzzahl
  • Long Integer (long)
  • Gleitkommawert
  • langer Gleitkommawert (doppelt)

Ein weiterer Datentyp, den Anbieter häufig verwenden, ist ein BLOB (Binary Large Object), das als 64 KB Byte-Array. Die verfügbaren Datentypen finden Sie in der Cursor-Klasse „get“ .

Der Datentyp für jede Spalte bei einem Anbieter ist normalerweise in der zugehörigen Dokumentation aufgeführt. Die Datentypen für den User Dictionary Provider sind in der Referenzdokumentation aufgeführt. für die Vertragsklasse UserDictionary.Words. Vertragsklassen sind wie im Abschnitt Vertragsklassen beschrieben. Sie können den Datentyp auch durch Aufrufen von Cursor.getType() ermitteln.

Anbieter speichern auch MIME-Datentypinformationen für jeden von ihnen definierten Inhalts-URI. Sie können können Sie anhand der MIME-Typ-Informationen herausfinden, ob Ihre Anwendung Daten verarbeiten kann, oder die Art der Handhabung basierend auf dem MIME-Typ wählen. In der Regel benötigen Sie MIME-Typ, wenn Sie mit einem Anbieter zusammenarbeiten, der komplexe Datenstrukturen oder Dateien.

Beispiel: ContactsContract.Data -Tabelle im Contacts Provider verwendet MIME-Typen, um den Typ der in den einzelnen Zeile. Um den MIME-Typ für einen Inhalts-URI abzurufen, rufen Sie folgenden Befehl auf: ContentResolver.getType()

Im Abschnitt MIME-Typ-Referenz wird beschrieben, Syntax von Standard- und benutzerdefinierten MIME-Typen.

Alternative Möglichkeiten des Anbieterzugriffs

Für die Anwendungsentwicklung sind drei alternative Formen des Anbieterzugriffs wichtig:

  • Batch-Zugriff: Sie können einen Batch von Zugriffsaufrufen mit den Methoden in ContentProviderOperation und wenden sie dann mit ContentResolver.applyBatch().
  • Asynchrone Abfragen: Führen Sie Abfragen in einem separaten Thread durch. Sie können Verwenden Sie ein CursorLoader-Objekt. Die Beispiele in den Ladeprogramm demonstrieren, wie das geht.
  • Datenzugriff mit Intents: Sie können jedoch keinen Intent senden. direkt an einen Anbieter senden, können Sie einen Intent an die Anwendung des Anbieters senden. am besten ausgerüstet sind, um die Daten des Anbieters zu modifizieren.

Der Batchzugriff und die Batch-Änderung mit Intents werden in den folgenden Abschnitten beschrieben.

Batch-Zugriff

Der Batchzugriff auf einen Anbieter eignet sich zum Einfügen einer großen Anzahl von Zeilen, in mehreren Tabellen im selben Methodenaufruf verwenden. Vorgänge über Prozessgrenzen hinweg als Transaktion, die als atomarer Vorgang bezeichnet wird.

So greifen Sie im Batchmodus auf einen Anbieter zu: ein Array mit ContentProviderOperation-Objekten und dann an einen Contentanbieter mit ContentResolver.applyBatch(). Sie bestehen am die Zertifizierungsstelle des Contentanbieters für diese Methode und nicht für einen bestimmten Inhalts-URI.

So funktioniert jedes ContentProviderOperation-Objekt im Array. mit einer anderen Tabelle vergleichen. Ein Aufruf von ContentResolver.applyBatch() gibt ein Array von Ergebnissen zurück.

Die Beschreibung der Vertragsklasse ContactsContract.RawContacts enthält ein Code-Snippet, das die Batch-Einfügung veranschaulicht.

Datenzugriff mit Intents

Intents können indirekten Zugriff auf einen Contentanbieter ermöglichen. Sie können dem Nutzer Zugriff auch wenn Ihre App keine Zugriffsberechtigungen hat. das Zurückgeben eines Ergebnis-Intents von einer Anwendung mit Berechtigungen oder durch Aktivieren eines -Anwendung, die über Berechtigungen verfügt und die der Nutzer darin arbeiten kann.

Zugriff mit temporären Berechtigungen erhalten

Sie können auch dann auf Daten bei einem Contentanbieter zugreifen, wenn Sie nicht die erforderlichen Zugriffsrechte haben. Berechtigungen, indem ein Intent an eine Anwendung gesendet wird, die über die einen Ergebnis-Intent mit URI-Berechtigungen zurückerhalten. Dies sind Berechtigungen für einen bestimmten Inhalts-URI, die bis zu der Aktivität gültig bleiben, die wenn sie abgeschlossen sind. Die Anwendung, die permanente Berechtigungen hat, gewährt vorübergehende Berechtigungen. indem Sie im Ergebnis-Intent ein Flag festlegen:

Hinweis:Diese Flags gewähren dem Anbieter keinen allgemeinen Lese- oder Schreibzugriff. deren Berechtigung im Inhalts-URI enthalten ist. Der Zugriff gilt nur für den URI selbst.

Wenn du Inhalts-URIs an eine andere App sendest, füge mindestens einen dieser URIs ein Flags. Die Flags stellen die folgenden Funktionen für jede Anwendung bereit, die eine Absicht haben und auf Android 11 (API-Level 30) oder höher ausgerichtet ist:

  • Aus den Daten lesen oder in diese schreiben, die der Inhalts-URI repräsentiert, abhängig von dem im Intent enthaltenen Flag.
  • Paket gewinnen Sichtbarkeit der App mit dem Contentanbieter, der mit dem URI-Befugnis. Die App, die den Intent sendet, und die App, die Contentanbieter zwei verschiedene Apps sein können.

Ein Anbieter definiert URI-Berechtigungen für Inhalts-URIs in seinem Manifest, indem er die android:grantUriPermissions des Tags <provider> -Element sowie das <grant-uri-permission> -Element der <provider> -Elements. Der URI-Berechtigungsmechanismus wird in der Leitfaden zu Berechtigungen unter Android

So können Sie beispielsweise Daten für einen Kontakt im Contacts Provider abrufen, auch wenn Sie haben die Berechtigung READ_CONTACTS. Vielleicht möchten Sie in einer Anwendung, die an Geburtstage E-Grüße an Kontakte sendet. Anstelle von READ_CONTACTS wird angefordert, wodurch Sie Zugriff auf alle Kontakte des Nutzers und alle zugehörigen Informationen zu verwalten, kann der Nutzer festlegen, Kontakte, die Ihre Anwendung verwendet. Gehen Sie dazu so vor:

  1. Senden Sie in der Anwendung einen Intent mit der Aktion. ACTION_PICK und die "Kontakte" MIME-Typ CONTENT_ITEM_TYPE mit dem startActivityForResult()-Methode.
  2. Da dieser Intent mit dem Intent-Filter für den "Auswahl" der Personen-App wird die Aktivität in den Vordergrund gestellt.
  3. In der Auswahlaktivität wählt die nutzende Person eine zu aktualisieren. In diesem Fall ruft die Auswahlaktivität setResult(resultcode, intent) um einen Intent zu erstellen, um Ihrer Anwendung etwas zurückzugeben. Der Intent enthält den Inhalts-URI den vom Nutzer ausgewählten Kontakt und die Flags FLAG_GRANT_READ_URI_PERMISSION Diese Flags gewähren URI Berechtigung für deine App, Daten des Kontakts zu lesen, auf den das Inhalts-URI. Die Auswahlaktivität ruft dann finish() auf, um die Kontrolle an Ihre Anwendung zurückgeben.
  4. Ihre Aktivität wird wieder in den Vordergrund verschoben und das System ruft die onActivityResult() . Diese Methode empfängt den Ergebnis-Intent, der von der Auswahlaktivität in App „Kontakte“.
  5. Mit dem Inhalts-URI aus dem Ergebnis-Intent können Sie die Daten des Kontakts lesen vom Contacts Provider, auch wenn Sie keine dauerhafte Berechtigung für den Lesezugriff angefordert haben in Ihrem Manifest an den Anbieter. Sie können dann das Geburtsdatum des Kontakts oder E-Mail-Adresse und senden Sie dann die Grußnachricht.

Andere Anwendung verwenden

Eine andere Möglichkeit, dem Nutzer die Möglichkeit zu geben, Daten zu ändern, für die Sie keine Zugriffsberechtigungen haben, besteht darin, eine Anwendung zu aktivieren, die über Berechtigungen verfügt, und dem Nutzer die Arbeit dort überlassen.

Die Kalenderanwendung akzeptiert z. B. ein ACTION_INSERT-Intent, mit dem Sie den -Benutzeroberfläche zum Einfügen. Sie können „Extras“ übergeben. in diesem Intent enthalten, die von der Anwendung um die Benutzeroberfläche vorab auszufüllen. Da wiederkehrende Termine eine komplexe Syntax haben, sollten können Sie Termine in den Kalenderanbieter einfügen, indem Sie die Kalender App mit einem ACTION_INSERT und lasse den Nutzer dann das Ereignis dort einfügen.

Daten mit einer Hilfs-App anzeigen

Wenn Ihre App Zugriffsberechtigungen hat, können Sie trotzdem ein Daten in einer anderen Anwendung anzuzeigen. Die Kalenderanwendung akzeptiert z. B. ein ACTION_VIEW-Intent, der ein bestimmtes Datum oder Ereignis anzeigt. Auf diese Weise können Sie Kalenderinformationen anzeigen, ohne eine eigene Benutzeroberfläche erstellen zu müssen. Weitere Informationen zu dieser Funktion finden Sie in der Übersicht des Kalenderanbieters

Die Anwendung, an die Sie den Intent senden, muss nicht die Anwendung sein die mit dem Anbieter verknüpft sind. Sie können beispielsweise einen Kontakt aus der Anbieter kontaktieren und dann den Intent ACTION_VIEW senden , der den Inhalts-URI für das Bild des Kontakts für eine Bildanzeige enthält.

Vertragsklassen

Eine Vertragsklasse definiert Konstanten, damit Anwendungen mit Inhalts-URIs arbeiten können. Spalte Namen, Absichtsaktionen und anderen Funktionen eines Contentanbieters. Vertragsklassen keine automatisch mit einem Anbieter verknüpft werden. Diese müssen vom Entwickler des Anbieters definiert werden. anderen Entwicklern zur Verfügung zu stellen. Viele der in der Android-App enthaltenen Anbieter Plattform hat entsprechende Vertragsklassen im Paket android.provider.

Der User Dictionary Provider verfügt beispielsweise über eine UserDictionary mit Inhalts-URI und Konstanten für Spaltennamen. Die Der Inhalts-URI für die Tabelle Words ist in der Konstante definiert UserDictionary.Words.CONTENT_URI. Die Klasse UserDictionary.Words enthält auch Konstanten für Spaltennamen, die in den Beispiel-Snippets in diesem Leitfaden verwendet werden. Eine Abfrageprojektion kann beispielsweise wie folgt definiert:

Kotlin

val projection : Array<String> = arrayOf(
        UserDictionary.Words._ID,
        UserDictionary.Words.WORD,
        UserDictionary.Words.LOCALE
)

Java

String[] projection =
{
    UserDictionary.Words._ID,
    UserDictionary.Words.WORD,
    UserDictionary.Words.LOCALE
};

Eine weitere Vertragsklasse ist ContactsContract für den Kontaktanbieter. Die Referenzdokumentation für diese Klasse enthält Beispielcode-Snippets. Eines der abgeleiteten Klassen, ContactsContract.Intents.Insert, ist ein Vertrag Klasse, die Konstanten für Intents und Intent-Daten enthält.

MIME-Typ-Referenz

Contentanbieter können Standard-MIME-Medientypen, benutzerdefinierte MIME-Typ-Strings oder beides zurückgeben.

MIME-Typen haben folgendes Format:

type/subtype

Der bekannte MIME-Typ text/html hat beispielsweise den Typ text und den Untertyp html. Wenn der Anbieter diesen Typ für einen URI zurückgibt, bedeutet dies, dass ein mit diesem URI gibt Text zurück, der HTML-Tags enthält.

Benutzerdefinierte MIME-Typ-Strings, auch anbieterspezifische MIME-Typen genannt, haben mehr komplexe type- und subtype-Werte. Bei mehreren Zeilen ist der Typwert immer der folgende:

vnd.android.cursor.dir

Für eine einzelne Zeile lautet der Typwert immer:

vnd.android.cursor.item

Die subtype ist anbieterspezifisch. Die Android-Anbieter haben in der Regel eine einfache . Wenn die Kontakte-Anwendung beispielsweise eine Zeile für eine Telefonnummer erstellt, wird der folgende MIME-Typ in der Zeile festgelegt:

vnd.android.cursor.item/phone_v2

Der Wert des Untertyps ist phone_v2.

Andere Entwickler können eigene Untertypen erstellen, die auf den Einstellungen des Anbieters basieren. Autoritäts- und Tabellennamen. Stellen Sie sich beispielsweise einen Anbieter mit Zugfahrplänen vor. Der Anbieter ist com.example.trains. Er enthält die Tabellen Line1, Line2 und Line3. Als Antwort auf den folgenden Inhalts-URI für Tabelle Line1:

content://com.example.trains/Line1

gibt der Anbieter den folgenden MIME-Typ zurück:

vnd.android.cursor.dir/vnd.example.line1

Als Antwort auf den folgenden Inhalts-URI für Zeile 5 in Tabelle Line2:

content://com.example.trains/Line2/5

gibt der Anbieter den folgenden MIME-Typ zurück:

vnd.android.cursor.item/vnd.example.line2

Die meisten Contentanbieter definieren Kontraktklassenkonstanten für die von ihnen verwendeten MIME-Typen. Die Kontaktklasse für Anbieter-Vertragsklasse ContactsContract.RawContacts, definiert zum Beispiel die Konstante CONTENT_ITEM_TYPE für den MIME-Typ von eine einzelne Rohkontaktzeile.

Inhalts-URIs für einzelne Zeilen werden in der Abschnitt Inhalts-URIs angezeigt.