Un fournisseur de contenu gère l'accès à un référentiel central de données. Vous implémentez un
comme une ou plusieurs classes dans une application Android, ainsi que les éléments dans
le fichier manifeste. L'une de vos classes implémente une sous-classe de
ContentProvider
, qui est l'interface entre votre fournisseur et
d'autres applications.
Bien que les fournisseurs de contenu soient conçus pour mettre des données à la disposition d'autres des activités qui permettent à l'utilisateur interroger et modifier les données gérées par votre fournisseur.
Cette page décrit les étapes de base à suivre pour créer un fournisseur de contenu et une liste d'API disponibles.
Avant de commencer à créer
Avant de commencer à créer un fournisseur, tenez compte des points suivants:
-
Déterminez si vous avez besoin d'un fournisseur de contenu. Vous devez créer un contenu
si vous souhaitez fournir une ou plusieurs des fonctionnalités suivantes:
<ph type="x-smartling-placeholder">
- </ph>
- Vous souhaitez proposer des données ou des fichiers complexes à d'autres applications.
- Vous souhaitez autoriser les utilisateurs à copier des données complexes de votre application vers d'autres.
- Vous souhaitez fournir des suggestions de recherche personnalisées à l'aide du framework de recherche.
- Vous souhaitez exposer les données de votre application à des widgets.
- Vous souhaitez implémenter
AbstractThreadedSyncAdapter
,CursorAdapter
ouCursorLoader
classes.
Vous n'avez pas besoin d'un fournisseur pour utiliser des bases de données ou d'autres types stockage persistant si l'utilisation relève entièrement de votre propre application et vous n'avez besoin d'aucune des fonctionnalités mentionnées ci-dessus. À la place, vous pouvez utilisez l'un des systèmes de stockage décrits Présentation du stockage des données et des fichiers
- Si vous ne l'avez pas déjà fait, consultez <ph type="x-smartling-placeholder"></ph> Principes de base des fournisseurs de contenu pour en savoir plus sur les fournisseurs et leur fonctionnement
Ensuite, procédez comme suit pour créer votre fournisseur:
-
Concevez le stockage brut pour vos données. Un fournisseur de contenu propose des données de deux manières:
<ph type="x-smartling-placeholder">
- </ph>
- Données de fichiers
- Les données qui sont normalement placées dans des fichiers, telles que des photos, de l'audio ou des vidéos. Stockez les fichiers dans l'espace de noms l'espace de stockage. En réponse à une demande de fichier provenant d'une autre application, votre peut proposer un handle vers le fichier.
- "Structuré" données
- Données qui sont normalement placées dans une base de données, un tableau ou une structure similaire. Stockez les données dans un format compatible avec les tables de lignes et de colonnes. Une ligne représente une entité, telle qu'une personne ou un article de l'inventaire. Une colonne représente certaines données pour l'entité, comme le nom d'une personne ou le prix d'un article. Un moyen courant de stocker ce type de données dans une base de données SQLite, mais vous pouvez utiliser n'importe quel type stockage persistant. Pour en savoir plus sur les types de stockage disponibles dans le système Android, consultez les section "Concevoir le stockage des données".
-
Définissez une implémentation concrète de la classe
ContentProvider
. les méthodes requises. Cette classe constitue l'interface entre vos données et le reste des Système Android. Pour plus d'informations sur ce cours, consultez la Implémentez la classe ContentProvider. - Définit la chaîne d'autorité du fournisseur, les URI de contenu et les noms de colonnes. Si vous voulez à l'application du fournisseur pour gérer les intents, définir des actions d'intent, des données supplémentaires, et les indicateurs. Définissez également les autorisations requises pour les applications pour accéder à vos données. Pensez à définir toutes ces valeurs comme des constantes dans une une classe de contrat distincte. Vous pourrez ensuite exposer cette classe à d'autres développeurs. Pour plus sur les URI de contenu, consultez la Concevoir des URI de contenu Pour en savoir plus sur les intents, consultez Intents et accès aux données.
-
Ajouter d'autres éléments facultatifs, tels que des exemples de données ou une implémentation
de
AbstractThreadedSyncAdapter
, qui peut synchroniser les données entre le fournisseur et les données dans le cloud.
Concevoir le stockage de données
Un fournisseur de contenu est l'interface permettant d'accéder aux données enregistrées dans un format structuré. Avant de créer l'interface, décidez comment stocker les données. Vous pouvez stocker les données sous la forme puis de concevoir l'interface pour lire et écrire les données si nécessaire.
Voici quelques-unes des technologies de stockage de données disponibles sur Android:
- Si vous travaillez avec des données structurées, envisagez d'utiliser soit une base de données relationnelle, comme SQLite ou un datastore non relationnel clé-valeur LevelDB : Si vous travaillez avec des données non structurées, telles que des fichiers audio, des images ou des contenus vidéo, puis envisagez de stocker données sous forme de fichiers. Vous pouvez combiner différents types de stockage et les exposer en faisant appel à un seul fournisseur de contenu, si nécessaire.
-
Le système Android peut interagir avec la bibliothèque de persistance Room, qui
donne accès à l'API de la base de données SQLite fournie par les fournisseurs d'Android
pour stocker des données orientées table. Pour créer une base de données à l'aide de cette
instanciez une sous-classe de
<ph type="x-smartling-placeholder"></ph>
RoomDatabase
, comme décrit dans Enregistrer des données dans une base de données locale à l'aide de RoomVous n'avez pas besoin d'utiliser une base de données pour implémenter votre dépôt. Un fournisseur apparaît en externe sous la forme d'un ensemble de tableaux, semblable à une base de données relationnelle, n'est pas obligatoire pour l'implémentation interne du fournisseur.
- Pour stocker les données de fichiers, Android dispose de diverses API orientées fichiers. Pour en savoir plus sur le stockage de fichiers, consultez la Présentation du stockage des données et des fichiers Si vous utilisez concevoir un fournisseur qui propose des données liées aux médias, comme la musique ou les vidéos, vous pouvez ont un fournisseur qui combine les données de table et les fichiers.
- Dans de rares cas, il peut être utile d'implémenter plusieurs fournisseurs de contenu pour pour une même application. Par exemple, vous pouvez partager des données avec un widget en utilisant un fournisseur de contenu, et un ensemble de données différent pour le partage applications.
-
Pour travailler avec des données basées sur le réseau, utilisez des classes dans
java.net
etandroid.net
Vous pouvez également synchroniser des données réseau telles qu'une base de données, puis de proposer les données sous forme de tables ou de fichiers.
Remarque: Si vous apportez à votre dépôt une modification rétrocompatible, vous devez marquer le dépôt avec une nouvelle version numéro. Vous devez également augmenter le numéro de version de votre application met en œuvre le nouveau fournisseur de contenu. Cette modification empêche le système les rétrogradations ne provoquent pas le plantage du système lors de la tentative de réinstallation Application dont le fournisseur de contenu n'est pas compatible
Considérations relatives à la conception des données
Voici quelques conseils pour concevoir la structure de données de votre fournisseur:
-
Les données de la table doivent toujours avoir une "clé primaire" colonne que le fournisseur gère
sous la forme d'une valeur numérique unique pour chaque ligne. Vous pouvez utiliser cette valeur pour associer la ligne
lignes dans d'autres tables (en l'utilisant comme "clé étrangère"). Même si vous pouvez utiliser n'importe quel nom
Pour cette colonne, il est préférable d'utiliser
BaseColumns._ID
car le fait d'associer les résultats d'une requête de fournisseurListView
exige que l'une des colonnes récupérées ait le nom_ID
-
Si vous souhaitez fournir des images bitmap ou d'autres éléments très volumineux de données orientées fichiers, stockez
les données d'un fichier, puis les fournir indirectement au lieu de les stocker directement dans un
tableau. Dans ce cas, vous devez indiquer aux utilisateurs de votre fournisseur qu'ils doivent utiliser un
ContentResolver
pour accéder aux données. -
Utilisez le type de données BLOB (Binary Large Object) pour stocker des données de taille variable ou ayant une
structure variable. Par exemple, vous pouvez utiliser une colonne BLOB pour stocker
tampon de protocole ou
Structure JSON :
Vous pouvez également utiliser un BLOB pour implémenter une table indépendante du schéma. Dans ce type de table, vous définissez une colonne de clé primaire, une colonne de type MIME, et une ou des colonnes plus génériques que BLOB. La signification des données des colonnes BLOB est indiquée par la valeur figurant dans la colonne "Type MIME". Cela vous permet de stocker différents types de lignes le même tableau. Les "données" du fournisseur de contacts tableau
ContactsContract.Data
est un exemple d'instance de VM indépendante du schéma. tableau.
Concevoir des URI de contenu
Un URI de contenu est un URI qui identifie les données d'un fournisseur. Les URI de contenu incluent
le nom symbolique de l'ensemble du fournisseur (son autorité) et un
qui pointe vers une table ou un fichier (un chemin d'accès). La partie facultative de l'ID pointe vers
une ligne individuelle dans un tableau. Chaque méthode d'accès aux données
ContentProvider
possède un URI de contenu comme argument. Cela vous permet
déterminer la table, la ligne ou le fichier auquel accéder.
Pour en savoir plus sur les URI de contenu, consultez <ph type="x-smartling-placeholder"></ph> Principes de base des fournisseurs de contenu
Concevoir une autorité
Un fournisseur dispose généralement d'une autorité unique, qui sert de nom interne à Android. À éviter les conflits avec d'autres fournisseurs, utiliser la propriété du domaine Internet (à l'envers) sur la base de votre autorité de fournisseur. Comme cette recommandation s'applique aussi à Android, vous pouvez définir votre autorité de fournisseur en tant qu'extension du nom du package contenant le fournisseur.
Par exemple, si le nom de votre package Android est
com.example.<appname>
, donnez à votre fournisseur le
autorité com.example.<appname>.provider
.
Concevoir une structure de tracé
Les développeurs créent généralement des URI de contenu à partir de l'autorité en ajoutant des chemins qui pointent vers
des tables individuelles. Par exemple, si vous avez deux tables, table1 et
table2, vous pouvez les combiner avec l'autorité de l'exemple précédent pour obtenir le résultat
URI de contenu
com.example.<appname>.provider/table1
et
com.example.<appname>.provider/table2
Les chemins d'accès ne sont pas
est limité à un seul segment. De plus, il n'est pas nécessaire de créer un tableau pour chaque niveau du chemin.
Gérer les ID d'URI de contenu
Par convention, les fournisseurs permettent d'accéder à une seule ligne d'une table en acceptant un URI de contenu
avec une valeur d'ID pour la ligne à la fin de l'URI. Par convention, les fournisseurs correspondent
"ID" dans la colonne _ID
de la table et effectuez l'accès demandé sur
ligne qui correspond.
Cette convention facilite un modèle de conception courant pour les applications accédant à un fournisseur. L'application
exécute une requête sur le fournisseur et affiche le résultat Cursor
.
dans un ListView
à l'aide d'un CursorAdapter
.
La définition de CursorAdapter
nécessite que l'une des colonnes de la propriété
Cursor
devient _ID
L'utilisateur sélectionne ensuite l'une des lignes affichées dans l'interface utilisateur pour consulter ou modifier la
données. L'application obtient la ligne correspondante à partir du Cursor
qui sauvegarde le
ListView
, obtient la valeur _ID
pour cette ligne et l'ajoute à
l'URI de contenu et envoie la demande d'accès au fournisseur. Le fournisseur peut alors effectuer
requête ou modification par rapport à la ligne exacte sélectionnée par l'utilisateur.
Formats d'URI de contenu
Pour vous aider à choisir l'action à effectuer pour un URI de contenu entrant, l'API du fournisseur inclut
La classe de commodité UriMatcher
, qui mappe les modèles d'URI de contenu
des valeurs entières. Vous pouvez utiliser les valeurs entières dans une instruction switch
qui
choisit l'action souhaitée pour le ou les URI de contenu qui correspondent à un format particulier.
Un modèle d'URI de contenu met en correspondance les URI de contenu à l'aide de caractères génériques:
-
*
correspond à une chaîne de n'importe quel caractère valide de n'importe quelle longueur. -
#
correspond à une chaîne de caractères numériques de n'importe quelle longueur.
Pour un exemple de conception et de codage de la gestion d'URI de contenu, prenons l'exemple d'un fournisseur avec le
l'autorité com.example.app.provider
qui reconnaît les URI de contenu suivants
pointant vers des tables:
-
content://com.example.app.provider/table1
: une table appeléetable1
. -
content://com.example.app.provider/table2/dataset1
: une table appeléedataset1
-
content://com.example.app.provider/table2/dataset2
: une table appeléedataset2
-
content://com.example.app.provider/table3
: une table appeléetable3
.
Le fournisseur reconnaît également ces URI de contenu s'ils sont associés à un ID de ligne, par exemple content://com.example.app.provider/table3/1
pour la ligne identifiée par
1
dans table3
.
Les formats d'URI de contenu suivants sont possibles:
-
content://com.example.app.provider/*
- Correspond à n'importe quel URI de contenu du fournisseur.
-
content://com.example.app.provider/table2/*
-
Correspond à un URI de contenu pour les tables
dataset1
etdataset2
, mais ne correspond pas aux URI de contenu pourtable1
outable3
-
content://com.example.app.provider/table3/#
-
Correspond à un URI de contenu
pour des lignes uniques dans
table3
, par exemplecontent://com.example.app.provider/table3/6
pour la ligne identifiée par6
L'extrait de code suivant montre le fonctionnement des méthodes dans UriMatcher
.
Ce code ne gère pas les URI d'une table entière différemment des URI d'une
ligne unique à l'aide du modèle d'URI de contenu
content://<authority>/<path>
pour les tables et
content://<authority>/<path>/<id>
pour des lignes individuelles.
La méthode addURI()
mappe
et le chemin d'accès à une valeur entière. La méthode match()
renvoie la valeur entière d'un URI. Une instruction switch
choisit entre interroger l'ensemble de la table
et interroger un seul enregistrement.
Kotlin
private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used * in the path. */ addURI("com.example.app.provider", "table3", 1) /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ addURI("com.example.app.provider", "table3/#", 2) } ... class ExampleProvider : ContentProvider() { ... // Implements ContentProvider.query() override fun query( uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String? ): Cursor? { var localSortOrder: String = sortOrder ?: "" var localSelection: String = selection ?: "" when (sUriMatcher.match(uri)) { 1 -> { // If the incoming URI was for all of table3 if (localSortOrder.isEmpty()) { localSortOrder = "_ID ASC" } } 2 -> { // If the incoming URI was for a single row /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ localSelection += "_ID ${uri?.lastPathSegment}" } else -> { // If the URI isn't recognized, // do some error handling here } } // Call the code to actually do the query } }
Java
public class ExampleProvider extends ContentProvider { ... // Creates a UriMatcher object. private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to one. No wildcard is used * in the path. */ uriMatcher.addURI("com.example.app.provider", "table3", 1); /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ uriMatcher.addURI("com.example.app.provider", "table3/#", 2); } ... // Implements ContentProvider.query() public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... /* * Choose the table to query and a sort order based on the code returned for the incoming * URI. Here, too, only the statements for table 3 are shown. */ switch (uriMatcher.match(uri)) { // If the incoming URI was for all of table3 case 1: if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; break; // If the incoming URI was for a single row case 2: /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ selection = selection + "_ID = " + uri.getLastPathSegment(); break; default: ... // If the URI isn't recognized, do some error handling here } // Call the code to actually do the query }
Une autre classe, ContentUris
, fournit des méthodes pratiques pour travailler
avec la partie id
des URI de contenu. Les classes Uri
et
Uri.Builder
incluent des méthodes pratiques pour analyser des
Uri
et en créer d'autres.
Implémenter la classe ContentProvider
L'instance ContentProvider
gère l'accès
à un ensemble structuré de données en traitant les requêtes provenant d'autres applications. Tous les formulaires
d'accès finissent par appeler ContentResolver
, qui appelle ensuite une instance
de ContentProvider
pour obtenir l'accès.
Méthodes requises
La classe abstraite ContentProvider
définit six méthodes abstraites qui
à implémenter dans votre sous-classe concrète. Toutes ces méthodes, sauf
Les éléments onCreate()
sont appelés par une application cliente.
qui tente d'accéder à votre fournisseur de contenu.
-
query()
-
Récupérer des données auprès de votre fournisseur Utilisez les arguments pour sélectionner la table
requête, les lignes et les colonnes à renvoyer et l'ordre de tri du résultat.
Renvoyez les données en tant qu'objet
Cursor
. -
insert()
- Insérez une nouvelle ligne dans votre fournisseur. Utilisez les arguments pour sélectionner table de destination et obtenir les valeurs de colonne à utiliser. Renvoyez un URI de contenu pour ligne qui vient d'être insérée.
-
update()
- Mettez à jour les lignes existantes de votre fournisseur. Utiliser les arguments pour sélectionner le tableau et les lignes de mettre à jour et d'obtenir les valeurs de colonne mises à jour. Renvoie le nombre de lignes mises à jour.
-
delete()
- Supprimez des lignes de votre fournisseur. Utilisez les arguments pour sélectionner le tableau et les lignes à supprimer. Renvoie le nombre de lignes supprimées.
-
getType()
- Renvoie le type MIME correspondant à un URI de contenu. Cette méthode est décrite consultez la section Implémenter les types MIME du fournisseur de contenu.
-
onCreate()
-
Initialisez votre fournisseur. Le système Android appelle cette méthode immédiatement après l'avoir
crée votre fournisseur. Votre fournisseur n'est créé
L'objet
ContentResolver
tente d'y accéder.
Ces méthodes ont la même signature que les méthodes portant un nom identique
ContentResolver
.
Votre implémentation de ces méthodes doit tenir compte des éléments suivants:
-
Toutes ces méthodes, sauf
onCreate()
peuvent être appelés par plusieurs threads à la fois, ils doivent donc être sécurisés. Pour apprendre sur les threads, consultez la <ph type="x-smartling-placeholder"></ph> Présentation des processus et des threads -
Évitez d'effectuer des opérations longues dans
onCreate()
. Différez les tâches d'initialisation jusqu'à ce qu'elles soient réellement nécessaires. La section sur l'implémentation de la méthode onCreate() à ce sujet plus en détail. -
Bien que vous deviez implémenter ces méthodes, votre code n'a rien à faire, sauf
renvoient le type de données attendu. Par exemple, vous pouvez empêcher les autres applications
d'insérer des données dans certaines tables en ignorant l'appel
insert()
et retour 0.
Implémenter la méthode query()
La
La méthode ContentProvider.query()
doit renvoyer un objet Cursor
. Si tel est le cas,
échoue, générez une Exception
. Si vous utilisez une base de données SQLite comme base de données
d'espace de stockage, vous pouvez renvoyer le Cursor
renvoyé par l'un des
Méthodes query()
de la classe SQLiteDatabase
.
Si la requête ne correspond à aucune ligne, renvoie un Cursor
Une instance dont la méthode getCount()
renvoie 0.
Ne renvoie null
que si une erreur interne s'est produite pendant le processus de requête.
Si vous n'utilisez pas de base de données SQLite comme stockage de données, utilisez l'une des sous-classes concrètes
sur Cursor
. Par exemple, la classe MatrixCursor
implémente un curseur dans lequel chaque ligne est un tableau d'instances Object
. Dans ce cours,
utilisez addRow()
pour ajouter une ligne.
Le système Android doit être en mesure de communiquer le Exception
au-delà des limites des processus. Android peut le faire pour les exceptions suivantes, qui sont utiles
dans la gestion des erreurs de requête:
-
IllegalArgumentException
. Vous pouvez choisir de le renvoyer reçoit un URI de contenu non valide. -
NullPointerException
Implémenter la méthode insert()
La méthode insert()
ajoute
nouvelle ligne dans la table appropriée, à l'aide des valeurs du ContentValues
. Si un nom de colonne ne figure pas dans l'argument ContentValues
, vous
fournir une valeur par défaut dans le code de votre fournisseur ou dans votre base de données
du schéma.
Cette méthode renvoie l'URI de contenu de la nouvelle ligne. Pour ce faire, ajoutez le code
la clé primaire de la ligne (généralement la valeur _ID
) à l'URI de contenu de la table, à l'aide de
withAppendedId()
Implémenter la méthode delete()
La méthode delete()
n'a pas besoin de supprimer des lignes
de votre espace de stockage. Si vous utilisez un adaptateur de synchronisation
avec votre fournisseur, pensez à marquer une ligne supprimée
avec une requête "delete" au lieu de supprimer complètement la ligne. L'adaptateur de synchronisation
rechercher les lignes supprimées et les retirer du serveur avant de les supprimer du fournisseur.
Implémenter la méthode update()
La méthode update()
utilise le même argument ContentValues
que celui utilisé par
insert()
et les
les mêmes arguments selection
et selectionArgs
utilisés par
delete()
et
ContentProvider.query()
Cela peut vous permettre de réutiliser du code entre ces méthodes.
Implémenter la méthode onCreate()
Le système Android appelle onCreate()
au démarrage du fournisseur. Effectuer uniquement une initialisation rapide
de cette méthode, et différer la création de la base de données et le chargement des données jusqu'à ce que le fournisseur
reçoit une requête de données. Si vous effectuez de
longues tâches dans
onCreate()
, vous ralentissez votre
la start-up d'un fournisseur. Cela ralentit la réponse du fournisseur à d'autres
applications.
Les deux extraits de code suivants
illustrent l'interaction entre
ContentProvider.onCreate()
et
<ph type="x-smartling-placeholder"></ph>
Room.databaseBuilder()
Le premier
l'extrait de code montre l'implémentation
ContentProvider.onCreate()
, où
de base de données est créé et les traitements associés aux objets d'accès aux données sont créés:
Kotlin
// Defines the database name private const val DBNAME = "mydb" ... class ExampleProvider : ContentProvider() { // Defines a handle to the Room database private lateinit var appDatabase: AppDatabase // Defines a Data Access Object to perform the database operations private var userDao: UserDao? = null override fun onCreate(): Boolean { // Creates a new database object appDatabase = Room.databaseBuilder(context, AppDatabase::class.java, DBNAME).build() // Gets a Data Access Object to perform the database operations userDao = appDatabase.userDao return true } ... // Implements the provider's insert method override fun insert(uri: Uri, values: ContentValues?): Uri? { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
Java
public class ExampleProvider extends ContentProvider // Defines a handle to the Room database private AppDatabase appDatabase; // Defines a Data Access Object to perform the database operations private UserDao userDao; // Defines the database name private static final String DBNAME = "mydb"; public boolean onCreate() { // Creates a new database object appDatabase = Room.databaseBuilder(getContext(), AppDatabase.class, DBNAME).build(); // Gets a Data Access Object to perform the database operations userDao = appDatabase.getUserDao(); return true; } ... // Implements the provider's insert method public Cursor insert(Uri uri, ContentValues values) { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
Implémenter les types MIME du ContentProvider
La classe ContentProvider
comporte deux méthodes pour renvoyer les types MIME:
-
getType()
- L'une des méthodes requises à implémenter pour n'importe quel fournisseur.
-
getStreamTypes()
- Méthode que vous devez implémenter si votre fournisseur propose des fichiers.
Types MIME pour les tables
La méthode getType()
renvoie une
String
au format MIME qui décrit le type de données renvoyé par le contenu
un argument d'URI. L'argument Uri
peut être un modèle plutôt qu'un URI spécifique.
Dans ce cas, renvoyez le type de données associé aux URI de contenu qui correspondent aux
du modèle.
Pour les types de données courants tels que
le texte, HTML ou JPEG,
getType()
renvoie la valeur
le type MIME de ces données. La liste complète de ces types de normes est disponible dans le
Types de médias MIME de l'IANA
sur votre site Web.
Pour les URI de contenu qui pointent vers une ou plusieurs lignes de données de table,
Retours pour getType()
Un type MIME au format MIME propre au fournisseur d'Android:
-
Partie du type:
vnd
-
Partie du sous-type:
<ph type="x-smartling-placeholder">
- </ph>
-
Si le format d'URI correspond à une seule ligne:
android.cursor.item/
-
Si le format d'URI correspond à plusieurs lignes:
android.cursor.dir/
-
Si le format d'URI correspond à une seule ligne:
-
Partie spécifique au fournisseur:
vnd.<name>
.<type>
Vous fournissez
<name>
et<type>
. La valeur<name>
est unique. et la valeur<type>
est unique dans l'URI correspondant du modèle. Un bon choix pour<name>
est le nom de votre entreprise ou une partie du nom du package Android de votre application. Un bon choix pour les<type>
est une chaîne qui identifie la table associée au URI.
Par exemple, si l'autorité d'un fournisseur est
com.example.app.provider
et expose une table nommée
table1
, le type MIME de plusieurs lignes dans table1
est le suivant:
vnd.android.cursor.dir/vnd.com.example.provider.table1
Pour une seule ligne de table1
, le type MIME est le suivant:
vnd.android.cursor.item/vnd.com.example.provider.table1
Types MIME pour les fichiers
Si votre fournisseur propose des fichiers, implémentez
getStreamTypes()
La méthode renvoie un tableau String
des types MIME pour les fichiers que votre fournisseur
peut renvoyer pour un URI de contenu donné. Filtrer les types MIME que vous proposez par type MIME
l'argument filter, de sorte que vous ne renvoyez que les types MIME que le client souhaite gérer.
Prenons l'exemple d'un fournisseur qui propose des photos
sous forme de fichiers JPG,
PNG et GIF.
Si une application appelle ContentResolver.getStreamTypes()
avec la chaîne de filtre image/*
, pour un élément qui
est une « image »,
la méthode ContentProvider.getStreamTypes()
renvoie alors le tableau:
{ "image/jpeg", "image/png", "image/gif"}
Si l'application ne s'intéresse qu'aux fichiers JPG, elle peut appeler
ContentResolver.getStreamTypes()
avec la chaîne de filtre *\/jpeg
;
getStreamTypes()
renvoie:
{"image/jpeg"}
Si votre fournisseur ne propose aucun des types MIME demandés dans la chaîne de filtre,
getStreamTypes()
renvoie null
.
Implémenter une classe de contrat
Une classe de contrat est une classe public final
qui contient des définitions constantes pour le
URI, noms de colonne, types MIME et autres métadonnées relatives au fournisseur. La classe
établit un contrat entre le fournisseur et d'autres applications en s'assurant que le fournisseur
sont accessibles correctement, même en cas de modification des valeurs réelles des URI, des noms de colonnes,
et ainsi de suite.
Une classe de contrat aide également les développeurs, car elle porte généralement des noms mnémotechniques pour ses constantes, les développeurs sont donc moins susceptibles d'utiliser des valeurs incorrectes pour les noms de colonne ou les URI. Puisqu'il s'agit d'un elle peut contenir de la documentation Javadoc. Les environnements de développement intégrés, Android Studio peut compléter automatiquement les noms des constantes de la classe de contrat et afficher Javadoc pour les constantes.
Les développeurs ne peuvent pas accéder au fichier de classe de la classe de contrat à partir de votre application, mais ils peuvent le compilent de manière statique dans leur application à partir d'un fichier JAR que vous fournissez.
La classe ContactsContract
et ses classes imbriquées sont des exemples de
classes contractuelles.
Implémenter des autorisations de fournisseur de contenu
Les autorisations et les accès pour tous les aspects du système Android sont décrits en détail dans Conseils de sécurité La présentation du stockage des données et des fichiers décrit la sécurité et les autorisations en vigueur pour les différents types de stockage. En résumé, les points importants sont les suivants:
- Par défaut, les fichiers de données stockés dans la mémoire de stockage interne de l'appareil sont privés de l'application et du fournisseur.
-
Les bases de données
SQLiteDatabase
que vous créez sont privées de l'application et du fournisseur. - Par défaut, les fichiers de données que vous enregistrez sur un espace de stockage externe sont publics et lisible au monde entier. Vous ne pouvez pas utiliser un fournisseur de contenu pour restreindre l'accès aux fichiers dans stockage externe, car d'autres applications peuvent utiliser d'autres appels d'API pour les lire et les écrire.
- La méthode appelle l'ouverture ou la création de fichiers ou de bases de données SQLite dans l'environnement interne de votre appareil. le stockage peut potentiellement donner un accès en lecture et en écriture à toutes les autres applications. Si vous utilisez un fichier ou une base de données interne comme référentiel, et vous lui donnez "lisible au monde entier" ou "inscriptible à tous" ; les autorisations que vous avez définies pour votre fournisseur son fichier manifeste ne protègent pas vos données. L'accès par défaut aux fichiers et aux bases de données dans la mémoire de stockage interne est "privée". ne le modifiez pas pour le dépôt de votre fournisseur.
Si vous souhaitez utiliser les autorisations du fournisseur de contenu pour contrôler l'accès à vos données, stocker vos données dans des fichiers internes, dans des bases de données SQLite ou dans le cloud, sur un serveur distant, et préserver la confidentialité des fichiers et des bases de données dans votre application.
Implémenter des autorisations
Par défaut, toutes les applications peuvent lire ou écrire sur votre fournisseur, même si les données sous-jacentes sont
privé, car par défaut votre fournisseur
n’a pas d’autorisations définies. Pour changer cela,
définissez les autorisations pour votre fournisseur dans votre fichier manifeste, à l'aide d'attributs ou d'éléments
de l'élément
<provider>
. Vous pouvez définir des autorisations
qui s'appliquent à l'ensemble du fournisseur,
à certaines tables, à certains enregistrements, ou aux trois.
Vous définissez des autorisations pour votre fournisseur
<permission>
dans votre fichier manifeste. Pour que le
autorisation propre à votre fournisseur, utilisez un champ d'application de style Java pour
android:name
. Par exemple, nommez l’autorisation de lecture
com.example.app.provider.permission.READ_PROVIDER
La liste suivante décrit le champ d'application des autorisations de fournisseur, en commençant par les autorisations qui s'appliquent à l'ensemble du fournisseur, puis de devenir plus précises. Les autorisations plus précises prévalent sur celles dont le champ d'application est plus étendu.
- Autorisation unique au niveau du fournisseur en lecture/écriture
-
Une autorisation qui contrôle à la fois l'accès en lecture et
en écriture à l'ensemble du fournisseur, spécifiée
avec l'attribut
android:permission
de<provider>
. - Séparer les autorisations de lecture et d'écriture au niveau du fournisseur
-
Une autorisation de lecture et une autorisation d'écriture pour l'ensemble du fournisseur. Vous les spécifiez
avec les
android:readPermission
et Attributsandroid:writePermission
de<provider>
. Elles prévalent sur l'autorisation requise parandroid:permission
- Autorisation au niveau du chemin d'accès
-
Autorisation de lecture, d'écriture ou de lecture/écriture pour un URI de contenu de votre fournisseur. Vous indiquez
chaque URI que vous souhaitez contrôler
Élément enfant
<path-permission>
de Élément<provider>
. Pour chaque URI de contenu que vous spécifiez, vous pouvez spécifier un une autorisation de lecture/écriture, une autorisation de lecture, une autorisation d’écriture, ou les trois. L'interface de lecture et les autorisations d'écriture prévalent sur l'autorisation de lecture/écriture. De plus, au niveau du chemin l'autorisation prévaut sur les autorisations définies au niveau du fournisseur. - Autorisation temporaire
-
Un niveau d'autorisation qui accorde un accès temporaire à une application, même si l'application
ne dispose pas des autorisations normalement requises. L'option "Temporaire"
réduit le nombre d'autorisations qu'une application doit demander dans
dans son fichier manifeste. Lorsque vous activez les autorisations temporaires, les seules applications qui ont besoin
des autorisations permanentes pour votre fournisseur
sont celles qui accèdent en permanence
vos données.
Par exemple, tenez compte des autorisations dont vous avez besoin si vous implémentez un fournisseur de messagerie et une application autoriser une application externe de visionneuse d'images à afficher les photos jointes à partir de votre un fournisseur de services agréé. Pour accorder au lecteur d'images l'accès nécessaire sans exiger d'autorisations, vous pouvez configurer des autorisations temporaires pour les URI de contenu des photos.
Concevez votre application de messagerie de sorte que que lorsque l'utilisateur souhaite afficher une photo, l'application envoie un intent contenant l'URI de contenu de la photo et les indicateurs d'autorisation associés à la visionneuse d'images. La visionneuse d'images puis demandez à votre fournisseur de messagerie de récupérer la photo, disposer de l'autorisation de lecture normale pour votre fournisseur.
Pour activer les autorisations temporaires, définissez le paramètre Attribut
android:grantUriPermissions
de<provider>
élément ou ajoutez-en un ou plusieurs<grant-uri-permission>
éléments enfants à votre<provider>
. AppelerContext.revokeUriPermission()
chaque fois que vous supprimez la prise en charge d'un URI de contenu associé à une autorisation temporaire dans votre un fournisseur de services agréé.La valeur de l'attribut détermine dans quelle mesure votre fournisseur est rendu accessible. Si l'attribut est défini sur
"true"
, le système accorde une autorisation temporaire l'autorisation pour l'ensemble de votre fournisseur, ignorant ainsi toutes les autres autorisations requises par les autorisations définies au niveau du fournisseur ou du chemin d'accès.Si cet indicateur est défini sur
"false"
, ajoutez<grant-uri-permission>
éléments enfants à votre<provider>
. Chaque élément enfant spécifie l'URI de contenu URI pour lesquels un accès temporaire est accordé.Pour déléguer un accès temporaire à une application, un intent doit contenir l'option
FLAG_GRANT_READ_URI_PERMISSION
, l'optionFLAG_GRANT_WRITE_URI_PERMISSION
, ou les deux. Ces sont définies avec la méthodesetFlags()
.Si l'attribut
android:grantUriPermissions
n'est pas présent, il est considéré comme"false"
<provider> élément
Comme les composants Activity
et Service
,
Une sous-classe de ContentProvider
est défini dans le fichier manifeste de son application, à l'aide de la méthode
<provider>
. Le système Android obtient les informations suivantes
l'élément:
-
Autorité
(
android:authorities
) - Noms symboliques qui identifient l'ensemble du fournisseur au sein du système. Ce est décrit plus en détail dans la Concevoir des URI de contenu
-
Nom de classe du fournisseur
(
android:name
) -
La classe qui implémente
ContentProvider
. Ce cours est décrit plus en détail dans le Implémentez la classe ContentProvider. - Autorisations
-
Attributs qui spécifient les autorisations que d'autres applications doivent avoir pour accéder
les données du fournisseur:
<ph type="x-smartling-placeholder">
- </ph>
-
android:grantUriPermissions
: indicateur d'autorisation temporaire -
android:permission
: autorisation de lecture/écriture au niveau du fournisseur unique -
android:readPermission
: autorisation de lecture au niveau du fournisseur -
android:writePermission
: autorisation d'écriture au niveau du fournisseur
Les autorisations et les attributs correspondants sont décrits consultez la documentation Section Implémenter les autorisations du fournisseur de contenu
-
- Attributs de démarrage et de contrôle
-
Ces attributs déterminent quand et comment le système Android lance le fournisseur,
les caractéristiques de processus du fournisseur, ainsi que d'autres paramètres d'exécution:
<ph type="x-smartling-placeholder">
- </ph>
-
android:enabled
: option permettant au système de démarrer le fournisseur -
android:exported
: option permettant à d'autres applications d'utiliser ce fournisseur -
android:initOrder
: ordre de démarrage du fournisseur par rapport à d'autres fournisseurs dans le même processus -
android:multiProcess
: option permettant au système de démarrer le fournisseur dans le même processus que le client appelant -
android:process
: nom du processus dans lequel le fournisseur exécute -
android:syncable
: indicateur indiquant que les données du fournisseur doivent être synchronisées avec des données sur un serveur
Ces attributs sont décrits en détail dans le guide Élément
<provider>
. -
- Attributs informatifs
-
Icône et libellé facultatifs pour le fournisseur:
<ph type="x-smartling-placeholder">
- </ph>
-
android:icon
: ressource drawable contenant une icône pour le fournisseur. L'icône s'affiche à côté du libellé du fournisseur dans la liste des applications dans Paramètres > Applications > Tout : -
android:label
: libellé informatif décrivant le fournisseur, ses données, ou les deux. Le libellé s'affiche dans la liste des applications dans Paramètres > Applications > Tout :
Ces attributs sont décrits en détail dans le guide Élément
<provider>
. -
Remarque:Si vous ciblez Android 11 ou une version ultérieure, consultez le documentation sur la visibilité des packages pour les besoins de configuration supplémentaires.
Intents et accès aux données
Les applications peuvent accéder indirectement à un fournisseur de contenu avec un Intent
.
L'application n'appelle aucune des méthodes de ContentResolver
ou
ContentProvider
Au lieu de cela, il envoie un intent
qui démarre une activité,
qui fait souvent partie de l'application
propre au fournisseur. L'activité de destination
est responsable de
récupérer et afficher les données dans son interface utilisateur.
Selon l'action de l'intent, l'activité de destination peut également inviter l'utilisateur à apporter des modifications aux données du fournisseur. Un intent peut aussi contenir des "extras" données affichées par l'activité de destination dans l'UI. L'utilisateur a alors la possibilité de modifier ces données avant de les utiliser pour modifier le des données dans le fournisseur.
Vous pouvez utiliser l'accès aux intents pour favoriser l'intégrité des données. Votre fournisseur peut dépendre sur l'insertion, la mise à jour et la suppression des données selon une logique métier strictement définie. Si En effet, laisser d'autres applications modifier directement vos données peut entraîner des données non valides.
Si vous souhaitez que les développeurs utilisent l'accès aux intents, veillez à le documenter minutieusement. Expliquer pourquoi il est préférable d'accéder à l'intent à l'aide de l'UI de votre application plutôt que d'essayer de et modifier les données avec leur code.
Le traitement d'un intent entrant qui souhaite modifier les données de votre fournisseur est identique à celui pour gérer d'autres intents. Pour en savoir plus sur l'utilisation des intents, consultez Intents et filtres d'intents :
Pour en savoir plus, consultez les Présentation du fournisseur d'agenda