Le fournisseur de contacts est un composant Android puissant et flexible qui gère le dépôt central de données sur les personnes de l'appareil. Le fournisseur de contacts est la source des données visibles dans l'application Contacts de l'appareil. Vous pouvez également accéder à ses données dans vos propres l'application et de transférer des données entre l'appareil et les services en ligne. Le fournisseur s'adapte un large éventail de sources de données et essaie de gérer autant de données que possible pour chaque personne, avec et cela rend son organisation complexe. C'est pourquoi l'API du fournisseur inclut un vaste ensemble de classes de contrat et d'interfaces qui facilitent à la fois la récupération des données et modification.
Ce guide décrit les éléments suivants :
- Structure de base du fournisseur
- Comment récupérer des données auprès du fournisseur
- Modifier les données du fournisseur
- Comment écrire un adaptateur pour synchroniser les données entre votre serveur et le Fournisseur de contacts.
Ce guide part du principe que vous connaissez les principes de base des fournisseurs de contenu Android. Pour en savoir plus sur les fournisseurs de contenu Android, consultez le guide Principes de base des fournisseurs de contenu.
Organisation du fournisseur de contacts
Le fournisseur de contacts est un composant de fournisseur de contenu Android. Il gère trois types de données sur une personne, chacun correspondant à une table proposée par le fournisseur, comme illustré dans la figure 1 :

Figure 1 : Structure de la table des fournisseurs de contacts.
Les trois tables sont communément appelées par les noms de leurs classes contractuelles. Les cours Vous pouvez définir des constantes pour les URI de contenu, les noms de colonnes et les valeurs de colonne utilisés par les tables:
-
ContactsContract.Contacts
tableau - Lignes représentant différentes personnes, sur la base d'agrégations de lignes de contacts brutes
-
ContactsContract.RawContacts
table - Lignes contenant un résumé des données d'une personne, spécifique à un compte utilisateur et à un type.
-
ContactsContract.Data
table - Lignes contenant les détails des contacts bruts, tels que les adresses e-mail ou les numéros de téléphone
Les autres tables représentées par des classes de contrat dans ContactsContract
sont des tables auxiliaires que le fournisseur de contacts utilise pour gérer ses opérations ou l'assistance
des fonctions spécifiques dans les contacts
ou les applications de téléphonie de l'appareil.
Contacts bruts
Un contact brut représente les données d'une personne provenant d'un seul type et d'un seul nom de compte. Comme le fournisseur de contacts autorise plusieurs services en ligne en tant que source d'une personne, le fournisseur de contacts autorise plusieurs contacts bruts pour une même personne. Plusieurs contacts bruts permettent également à un utilisateur de combiner les données d'une personne provenant de plusieurs comptes du même type.
La plupart des données d'un contact brut ne sont pas stockées dans la table ContactsContract.RawContacts
. Elles sont stockées dans un ou plusieurs
lignes dans la table ContactsContract.Data
. Chaque ligne de données comporte une colonne Data.RAW_CONTACT_ID
contenant la valeur RawContacts._ID
de sa ligne ContactsContract.RawContacts
parente.
Colonnes importantes des contacts bruts
Les colonnes importantes de la table ContactsContract.RawContacts
sont listées dans le tableau 1. Veuillez lire les notes qui suivent le tableau :
Tableau 1. Colonnes importantes des contacts bruts.
Nom de la colonne | Utiliser | Notes |
---|---|---|
ACCOUNT_NAME
|
Nom du type de compte qui est la source de ce contact brut.
Par exemple, le nom d'un compte Google correspond à l'une des adresses Gmail du propriétaire de l'appareil
des adresses IP externes. Reportez-vous à la
prochaine entrée pour
ACCOUNT_TYPE pour plus
des informations.
|
Le format de ce nom est spécifique au type de compte. Il ne s'agit pas nécessairement d'une adresse e-mail. |
ACCOUNT_TYPE
|
Type de compte à l'origine de ce contact brut. Par exemple, le compte
type de compte Google est com.google . Évaluez toujours votre type de compte
par l'identifiant d'un domaine que vous possédez ou contrôlez. Cela garantit que votre type de compte est unique.
|
Un type de compte qui propose des données de contact est généralement associé à un adaptateur de synchronisation qui se synchronise avec le fournisseur de contacts. |
DELETED
|
Indicateur "deleted" (supprimé) pour un contact brut. | Cet indicateur permet au fournisseur de contacts de conserver la ligne en interne jusqu'à ce que les adaptateurs de synchronisation puissent la supprimer de leurs serveurs, puis de la supprimer définitivement du dépôt. |
Notes
Vous trouverez ci-dessous des remarques importantes concernant le
Table ContactsContract.RawContacts
:
-
Le nom d'un contact brut n'est pas stocké dans sa ligne dans
ContactsContract.RawContacts
. Au lieu de cela, il est stocké dans la tableContactsContract.Data
, dans une ligneContactsContract.CommonDataKinds.StructuredName
. Un contact brut ne comporte qu'une seule ligne de ce type dans le tableauContactsContract.Data
. -
Attention : Pour utiliser les données de votre propre compte dans une ligne de contact brute, vous devez :
être d'abord enregistré auprès de
AccountManager
. Pour ce faire, invitez aux utilisateurs d'ajouter le type de compte et le nom de leur compte à la liste des comptes. Si vous ne le faites pas, le fournisseur de contacts supprimera automatiquement votre ligne de contact brute.Par exemple, si vous souhaitez que votre application gère les données de contact de votre service Web avec le domaine
com.example.dataservice
et que le compte de l'utilisateur pour votre service estbecky.sharp@dataservice.example.com
, l'utilisateur doit d'abord ajouter le "type" (com.example.dataservice
) et le "nom" (becky.smart@dataservice.example.com
) du compte avant que votre application puisse ajouter des lignes de contact brutes. Vous pouvez expliquer cette exigence à l'utilisateur dans la documentation, ou vous pouvez demander à l' pour ajouter le type et/ou le nom. Les types et noms de comptes sont décrits plus en détail dans la section suivante.
Sources de données de contacts brutes
Pour comprendre le fonctionnement des contacts bruts, prenons l'utilisateur « Emily Dickinson ». qui a ce qui suit : trois comptes utilisateur définis sur son appareil:
emily.dickinson@gmail.com
emilyd@gmail.com
- Compte Twitter "belle_of_amherst"
Cet utilisateur a activé la synchronisation des contacts pour chacun de ces trois comptes dans les paramètres Comptes.
Supposons qu'Emily Dickinson ouvre une fenêtre de navigateur, se connecte à Gmail en tant que
emily.dickinson@gmail.com
, ouvertures
Contacts, puis ajoute "Thomas Higginson". Plus tard, elle se connecte à Gmail en tant que
emilyd@gmail.com
et envoie un e-mail à "Thomas Higginson", qui lui-même
l'ajoute comme contact. Elle suit également "colonel_tom". (identifiant Twitter de Thomas Higginson) sur
Twitter
Le fournisseur de contacts crée trois contacts bruts à la suite de ce travail :
-
Un contact brut pour "Thomas Higginson" associé à
emily.dickinson@gmail.com
. Le type de compte utilisateur est Google. -
Deuxième contact brut pour "Thomas Higginson" associé à
emilyd@gmail.com
. Le type de compte utilisateur est également Google. Il existe un deuxième contact brut, même si le nom est identique à un nom précédent, car la personne a été ajoutée pour un autre compte utilisateur. - Un troisième contact brut pour "Thomas Higginson" associé à "belle_of_amherst". Le type de compte utilisateur est Twitter.
Données
Comme indiqué précédemment, les données d'un contact brut sont stockées dans un
Ligne ContactsContract.Data
associée aux coordonnées brutes du contact
Valeur _ID
. Cela permet à un seul contact brut d'avoir plusieurs instances du même
tels que des adresses e-mail ou des numéros de téléphone. Par exemple, si
"Thomas Higginson" pour emilyd@gmail.com
(ligne de contact brute pour Thomas Higginson)
associé au compte Google emilyd@gmail.com
) possède une adresse e-mail personnelle de
thigg@gmail.com
et une adresse e-mail professionnelle de
thomas.higginson@gmail.com
, le fournisseur de contacts stocke les deux adresses e-mail
et les associe au contact brut.
Notez que différents types de données sont stockés dans cette seule table. Nom à afficher,
le numéro de téléphone, l'adresse e-mail, l'adresse postale, la photo et les informations détaillées sur le site Web.
ContactsContract.Data
. Pour vous aider,
La table ContactsContract.Data
contient des colonnes avec des noms descriptifs.
et d'autres avec des noms génériques. Le contenu d'une colonne de nom descriptif a la même signification, quel que soit le type de données de la ligne, tandis que le contenu d'une colonne de nom générique a une signification différente en fonction du type de données.
Noms de colonnes descriptifs
Voici quelques exemples de noms de colonnes descriptifs:
-
RAW_CONTACT_ID
-
Valeur de la colonne
_ID
du contact brut pour ces données. -
MIMETYPE
-
Type de données stockées sur cette ligne, exprimé sous la forme d'un type MIME personnalisé. Contacts Provider
utilise les types MIME définis dans les sous-classes de
ContactsContract.CommonDataKinds
Ces types MIME sont open source et peuvent être utilisés par n'importe quelle application ou adaptateur de synchronisation compatible avec le fournisseur de contacts. -
IS_PRIMARY
-
Si ce type de ligne de données peut apparaître plusieurs fois pour un contact brut, le
Indicateurs de colonne
IS_PRIMARY
la ligne de données qui contient les données principales pour le type. Par exemple, si l'utilisateur appuie de manière prolongée sur un numéro de téléphone d'un contact et sélectionne Définir comme valeur par défaut, la colonneIS_PRIMARY
de la ligneContactsContract.Data
contenant ce numéro est définie sur une valeur non nulle.
Noms de colonnes génériques
Il existe 15 colonnes génériques nommées DATA1
à
DATA15
disponibles pour tous les utilisateurs, ainsi que quatre autres options génériques
colonnes SYNC1
à SYNC4
qui ne doivent être utilisées que pour la synchronisation
adaptateurs. Les constantes de nom de colonne génériques fonctionnent toujours, quel que soit le type de
les données de la ligne.
La colonne DATA1
est indexée. Le fournisseur de contacts utilise toujours cette colonne pour
les données attendues par le fournisseur seront
la cible la plus fréquente d'une requête. Par exemple :
dans une ligne d'adresse e-mail, cette colonne contient l'adresse e-mail réelle.
Par convention, la colonne DATA15
est réservée au stockage de données BLOB (Binary Large Object), telles que des miniatures de photos.
Noms de colonnes spécifiques à un type
Pour faciliter l'utilisation des colonnes d'un type de ligne particulier, le fournisseur de contacts
fournit également des constantes de nom de colonne spécifiques au type, définies dans des sous-classes de
ContactsContract.CommonDataKinds
Les constantes donnent simplement un nom de constante différent au même nom de colonne, ce qui vous permet d'accéder aux données d'une ligne d'un type particulier.
Par exemple, la classe ContactsContract.CommonDataKinds.Email
définit
Constantes de nom de colonne spécifiques au type pour une ligne ContactsContract.Data
dont le type MIME est
Email.CONTENT_ITEM_TYPE
La classe contient la constante ADDRESS
pour la colonne d'adresse e-mail. La valeur réelle de
ADDRESS
correspond à "data1", ce qui signifie
identique au nom générique de la colonne.
Attention:N'ajoutez pas vos propres données personnalisées au
ContactsContract.Data
à l'aide d'une ligne comportant l'un des
aux types MIME prédéfinis du fournisseur. Sinon, vous risquez de perdre les données ou d'amener le fournisseur
un dysfonctionnement. Par exemple, vous ne devez pas ajouter de ligne avec le type MIME Email.CONTENT_ITEM_TYPE
contenant un nom d'utilisateur au lieu d'une adresse e-mail dans la colonne DATA1
. Si vous utilisez votre propre type MIME personnalisé pour la ligne, vous êtes libre
pour définir des noms de colonnes spécifiques à un type et utiliser les colonnes comme vous le souhaitez.
La figure 2 illustre la façon dont les colonnes descriptives et les colonnes de données apparaissent dans un
ContactsContract.Data
ligne et la façon dont les noms de colonnes spécifiques à un type sont "superposés"
les noms de colonnes génériques

Figure 2. Noms de colonnes spécifiques au type et noms de colonnes génériques.
Classes de noms de colonnes spécifiques au type
Le tableau 2 liste les classes de nom de colonne spécifiques au type les plus couramment utilisées:
Tableau 2. Classes de noms de colonnes spécifiques à un type
Classe de mappage | Type de données | Notes |
---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
Données relatives au nom du contact brut associé à cette ligne de données. | Un contact brut ne comporte qu'une seule de ces lignes. |
ContactsContract.CommonDataKinds.Photo |
Photo principale du contact brut associé à cette ligne de données. | Un contact brut ne comporte qu'une seule de ces lignes. |
ContactsContract.CommonDataKinds.Email |
Adresse e-mail du contact brut associé à cette ligne de données. | Un contact brut peut avoir plusieurs adresses e-mail. |
ContactsContract.CommonDataKinds.StructuredPostal |
Adresse postale du contact brut associé à cette ligne de données. | Un contact brut peut avoir plusieurs adresses postales. |
ContactsContract.CommonDataKinds.GroupMembership |
Identifiant qui associe le contact brut à l'un des groupes du fournisseur de contacts. | Les groupes sont une fonctionnalité facultative d'un type de compte et d'un nom de compte. Ils sont décrits plus en détail dans la section Groupes de contacts. |
Contacts
Le fournisseur de contacts combine les lignes de contact brutes de tous les types et noms de comptes pour former un contact. Cela permet d'afficher et de modifier toutes les données qu'un utilisateur a collectées pour une personne. Le fournisseur de contacts gère la création des contacts et l'agrégation des contacts bruts avec une ligne de contact existante. Ni les applications ni les adaptateurs de synchronisation ne sont autorisés à ajouter des contacts, et certaines colonnes d'une ligne de contact sont en lecture seule.
Remarque:Si vous essayez d'ajouter un contact à Contacts Provider avec un
insert()
, vous bénéficiez de
une exception UnsupportedOperationException
. Si vous essayez de mettre
à jour une colonne
qui est répertorié comme « en lecture seule », la mise à jour est ignorée.
Le fournisseur de contacts crée un contact en réponse à l'ajout d'un nouveau contact brut. qui ne correspond à aucun contact existant. Le fournisseur effectue également cette opération si une instance les données du contact changent de telle sorte qu'elles ne correspondent plus au contact auquel il était précédemment associés. Si une application ou un adaptateur de synchronisation crée un contact brut qui correspond à un contact existant, le nouveau contact brut est agrégé au contact existant.
Le fournisseur de contacts associe une ligne de contact à ses lignes de contact brutes à l'aide de la colonne _ID
de la ligne de contact dans le tableau Contacts
. Colonne CONTACT_ID
de la table des contacts bruts
ContactsContract.RawContacts
contient _ID
valeurs pour
la ligne de contacts associée
à chaque ligne de contacts bruts.
La table ContactsContract.Contacts
comporte également la colonne LOOKUP_KEY
, qui est un lien "permanent" vers la ligne de contact. Comme le fournisseur de contacts gère les contacts
automatiquement, la valeur _ID
d'une ligne de contact peut être modifiée
en réponse à une agrégation ou une synchronisation. Même si cela se produit, l'URI de contenu
CONTENT_LOOKUP_URI
combiné à
LOOKUP_KEY
du contact continuera
pointez vers la ligne de contact, ce qui vous permet
LOOKUP_KEY
pour conserver les liens vers les favoris des contacts, etc. Cette colonne a son propre format, qui n'a aucun lien avec celui de la colonne _ID
.
La figure 3 montre comment les trois tableaux principaux sont liés les uns aux autres.

Figure 3. Relations entre les tables "Contacts", "Contacts bruts" et "Détails".
Attention : Si vous publiez votre application sur le Google Play Store ou si elle est installée sur un appareil équipé d'Android 10 (niveau d'API 29) ou version ultérieure, gardez à l'esprit qu'un ensemble limité de champs et de méthodes de données de contacts sont obsolètes.
Dans les conditions mentionnées, le système efface régulièrement les valeurs dans ces champs de données:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
Les API utilisées pour définir les champs de données ci-dessus sont également obsolètes:
En outre, les champs suivants ne renvoient plus les contacts fréquents. Notez que certains de ces champs n'influencent le classement des contacts que lorsqu'ils font partie d'un type de données spécifique.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(affecte uniquement Adresse e-mail, Téléphone, Appelable, et Contactables types de données) -
ENTERPRISE_CONTENT_FILTER_URI
(n'affecte que les types de données Adresse e-mail, Téléphone et Appelable)
Si vos applications accèdent à ces champs ou API ou les mettent à jour, utilisez des méthodes alternatives. Par exemple, vous pouvez répondre à certains cas d'utilisation en utilisant des fournisseurs de contenu privés ou d'autres données stockées dans votre application ou vos systèmes backend.
Pour vérifier que le fonctionnement de votre application n'est pas affecté par ce changement, procédez comme suit : vous pouvez effacer manuellement ces champs de données. Pour ce faire, exécutez l'ADB suivant sur un appareil équipé d'Android 4.1 (niveau d'API 16) ou version ultérieure:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
Données des adaptateurs de synchronisation
Les utilisateurs saisissent leurs données de contacts directement dans l'appareil, mais ces données sont également transmises aux contacts
Fournisseur des services Web via des adaptateurs de synchronisation, qui automatisent
le transfert de données entre l'appareil et les services. Les adaptateurs de synchronisation s'exécutent en arrière-plan
sous le contrôle du système et appellent les méthodes ContentResolver
.
pour gérer les données.
Dans Android, le service Web avec lequel un adaptateur de synchronisation fonctionne est identifié par un type de compte. Chaque adaptateur de synchronisation fonctionne avec un type de compte, mais il peut accepter plusieurs noms de compte pour de ce type. Les types et noms de comptes sont décrits brièvement dans la section Sources de données de contacts brutes. Les définitions suivantes proposent plus en détail et décrire le lien entre le type et le nom du compte et les adaptateurs et services de synchronisation.
- Type de compte
-
Identifie un service dans lequel l'utilisateur a stocké des données. La plupart du temps, l'utilisateur doit
s'authentifier auprès du service. Par exemple, Google Contacts est un type de compte, identifié par le code
google.com
. Cette valeur correspond au type de compte utilisé parAccountManager
. - Nom du compte
- Identifie un compte ou un identifiant de connexion spécifique pour un type de compte. Les comptes Google Contacts sont identiques aux comptes Google, qui utilisent une adresse e-mail comme nom de compte. D'autres services peuvent utiliser un nom d'utilisateur ou un identifiant numérique composé d'un seul mot.
Les types de comptes ne doivent pas nécessairement être uniques. Un utilisateur peut configurer plusieurs comptes Google Contacts et télécharger leurs données vers le fournisseur de contacts ; cela peut se produire si l'utilisateur a un ensemble de des contacts personnels pour un nom de compte personnel et un autre pour le travail. Les noms de compte sont généralement uniques. Ensemble, ils identifient un flux de données spécifique entre le fournisseur de contacts un service externe.
Si vous souhaitez transférer les données de votre service à Contacts Provider, vous devez écrire vos votre propre adaptateur de synchronisation. Pour en savoir plus, consultez la section Adaptateurs de synchronisation du fournisseur de contacts.
La figure 4 montre comment Contacts Provider s'intègre au flux de données. sur les personnes. Dans le champ portant la mention "Adaptateurs de synchronisation", chaque adaptateur est étiqueté par son type de compte.

Figure 4. Flux de données du fournisseur de contacts.
Autorisations requises
Les applications qui souhaitent accéder au fournisseur de contacts doivent demander les autorisations suivantes :
- Accès en lecture à une ou plusieurs tables
-
READ_CONTACTS
, spécifié dansAndroidManifest.xml
avec l'élément<uses-permission>
comme<uses-permission android:name="android.permission.READ_CONTACTS">
. - Accès en écriture à une ou plusieurs tables
-
WRITE_CONTACTS
, spécifié dansAndroidManifest.xml
avec le<uses-permission>
en tant que<uses-permission android:name="android.permission.WRITE_CONTACTS">
Ces autorisations ne s'étendent pas aux données du profil utilisateur. Le profil utilisateur et ses autorisations requises sont abordés dans la section suivante, Profil utilisateur.
N'oubliez pas que les données de contact de l'utilisateur sont personnelles et sensibles. Les utilisateurs sont soucieux de leur confidentialité et ne veulent pas que les applications collectent des données les concernant ou concernant leurs contacts. Si vous ne comprenez pas pourquoi vous avez besoin d'une autorisation pour accéder aux données de ses contacts, il peut vous donner de mauvaises notes pour votre application ou refuser tout simplement de l'installer.
Profil utilisateur
La table ContactsContract.Contacts
comporte une seule ligne contenant les données de profil de l'utilisateur de l'appareil. Ces données décrivent plutôt le user
de l'appareil
plusieurs contacts de l'utilisateur. La ligne des contacts du profil est associée à un profil brut
de contacts pour chaque système utilisant un profil.
Chaque ligne de contact brut du profil peut comporter plusieurs lignes de données. Constantes pour accéder à l'utilisateur
sont disponibles dans la classe ContactsContract.Profile
.
L'accès au profil utilisateur nécessite des autorisations spéciales. En plus des
READ_CONTACTS
et
Autorisations WRITE_CONTACTS
nécessaires pour lire et écrire, accéder
au profil utilisateur nécessite les autorisations android.Manifest.permission#READ_PROFILE et
android.Manifest.permission#WRITE_PROFILE autorisations d'accès en lecture et en écriture,
respectivement.
N'oubliez pas que le profil d'un utilisateur doit être considéré comme sensible. L'autorisation android.Manifest.permission#READ_PROFILE vous permet d'accéder au compte de l'utilisateur permettant d'identifier personnellement l'utilisateur. Assurez-vous d'indiquer à l'utilisateur pourquoi vous avez besoin d'autorisations d'accès au profil utilisateur dans la description de votre application.
Pour récupérer la ligne de contact contenant le profil de l'utilisateur, appelez ContentResolver.query()
. Définissez l'URI de contenu sur CONTENT_URI
et ne fournissez aucun critère de sélection. Vous pouvez également utiliser cet URI de contenu comme URI de base pour récupérer des données
les contacts ou les données du profil. Par exemple, cet extrait de code récupère des données pour le profil:
Kotlin
// Sets the columns to retrieve for the user profile projection = arrayOf( ContactsContract.Profile._ID, ContactsContract.Profile.DISPLAY_NAME_PRIMARY, ContactsContract.Profile.LOOKUP_KEY, ContactsContract.Profile.PHOTO_THUMBNAIL_URI ) // Retrieves the profile from the Contacts Provider profileCursor = contentResolver.query( ContactsContract.Profile.CONTENT_URI, projection, null, null, null )
Java
// Sets the columns to retrieve for the user profile projection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.LOOKUP_KEY, Profile.PHOTO_THUMBNAIL_URI }; // Retrieves the profile from the Contacts Provider profileCursor = getContentResolver().query( Profile.CONTENT_URI, projection , null, null, null);
Remarque:Si vous récupérez plusieurs lignes de contacts et que vous souhaitez déterminer si l'une d'entre elles
est le profil utilisateur, testez
IS_USER_PROFILE
. Cette colonne est définie sur "1" si le contact correspond au profil utilisateur.
Métadonnées du fournisseur de contacts
Le fournisseur de contacts gère les données qui permettent de suivre l'état des données de contact dans le dépôt. Ces métadonnées sur le dépôt sont stockées à divers endroits, y compris dans les lignes des tables "Contacts bruts", "Données" et "Contacts", la table ContactsContract.Settings
et la table ContactsContract.SyncState
. Le tableau suivant présente les
de chacun de ces éléments de métadonnées:
Tableau 3 : Métadonnées dans le fournisseur de contacts
Tableau | Colonne | Valeurs | Signification |
---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
"0" : n'a pas été modifié depuis la dernière synchronisation. |
Marque les contacts bruts qui ont été modifiés sur l'appareil et doivent être synchronisés de nouveau avec le
Google Cloud. La valeur est définie automatiquement par le fournisseur de contacts lorsque les applications Android mettent à jour une ligne.
Les adaptateurs de synchronisation qui modifient les tables de données ou de contacts bruts doivent toujours ajouter le paramètre
la chaîne |
"1" : modifié depuis la dernière synchronisation, doit être synchronisé à nouveau avec le serveur. | |||
ContactsContract.RawContacts |
VERSION |
Numéro de version de cette ligne. | Contacts Provider incrémente automatiquement cette valeur chaque fois que la ligne ou les modifications de données associées. |
ContactsContract.Data |
DATA_VERSION |
Numéro de version de cette ligne. | Contacts Provider incrémente automatiquement cette valeur chaque fois que la ligne de données est modifié. |
ContactsContract.RawContacts |
SOURCE_ID |
Valeur de chaîne qui identifie de manière unique ce contact brut dans le compte dans dans lequel il a été créé. |
Lorsqu'un adaptateur de synchronisation crée un contact brut, cette colonne doit être définie sur la
l'identifiant unique du serveur pour le contact brut. Lorsqu'une application Android crée un contact brut, elle doit laisser cette colonne vide. Cela indique que la synchronisation
qu'il doit créer un nouveau contact brut sur le serveur et obtenir
pour SOURCE_ID .
Plus précisément, l'ID de la source doit être unique pour chaque compte. et doit être stable entre les synchronisations:
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" : les contacts de ce groupe ne doivent pas être visibles dans les UI des applications Android. | Cette colonne est destinée à la compatibilité avec les serveurs qui permettent à un utilisateur de masquer des contacts dans certains groupes. |
"1" : les contacts de ce groupe peuvent être visibles dans les UI des applications. | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" - Pour ce compte et ce type de compte, les contacts n'appartenant à aucun groupe sont invisibles pour les interfaces d'application Android. |
Par défaut, les contacts sont invisibles si aucun de leurs contacts bruts n'appartient à un groupe.
(L'appartenance à un groupe d'un contact brut est indiquée par un ou plusieurs
ContactsContract.CommonDataKinds.GroupMembership lignes
dans la table ContactsContract.Data ).
En définissant cet indicateur dans la ligne ContactsContract.Settings du tableau
pour un type de compte et un compte donnés, vous pouvez forcer la visibilité des contacts sans groupe.
Cet indicateur permet, par exemple, d'afficher les contacts des serveurs qui n'utilisent pas de groupes.
|
"1" : pour ce compte et ce type de compte, les contacts qui n'appartiennent pas à un groupe sont visibles par les UI de l'application. | |||
ContactsContract.SyncState |
(toutes) | Utilisez ce tableau pour stocker les métadonnées de votre adaptateur de synchronisation. | Cette table vous permet de stocker de manière persistante l'état de synchronisation et d'autres données liées à la synchronisation sur l'appareil. |
Accès au fournisseur de contacts
Cette section décrit les consignes d'accès aux données du fournisseur de contacts, en mettant l'accent sur les points suivants :
- Requêtes d'entités.
- Modification par lot.
- Récupération et modification avec des intents
- Intégrité des données
La procédure de modification d'un adaptateur de synchronisation est également expliquée plus en détail dans la section Adaptateurs de synchronisation Contacts Provider.
Interroger des entités
Étant donné que les tables du fournisseur de contacts sont organisées de manière hiérarchique, il est souvent utile de récupérer une ligne et toutes les lignes "enfants" qui y sont associées. Par exemple, pour afficher
toutes les informations d'une personne, vous pouvez récupérer
ContactsContract.RawContacts
lignes pour un seul
ContactsContract.Contacts
, ou toutes les
ContactsContract.CommonDataKinds.Email
lignes pour un seul
Ligne ContactsContract.RawContacts
. Pour faciliter cela, le fournisseur de contacts propose des constructions entité, qui agissent comme des jointures de base de données entre les tables.
Une entité est comme une table composée de colonnes sélectionnées d'une table parente et de sa table enfant.
Lorsque vous interrogez une entité, vous fournissez une projection et des critères de recherche basés sur les colonnes
disponibles auprès de l'entité. Le résultat est un Cursor
contenant
une ligne pour chaque ligne de la table enfant qui a été récupérée. Par exemple, si vous lancez une requête
ContactsContract.Contacts.Entity
pour le nom d'un contact
et toutes les lignes ContactsContract.CommonDataKinds.Email
pour toutes les
contacts bruts pour ce nom, vous obtenez une Cursor
contenant une ligne
pour chaque ligne ContactsContract.CommonDataKinds.Email
.
Les entités simplifient les requêtes. À l'aide d'une entité, vous pouvez récupérer toutes les données de contact d'un contact ou d'un contact brut en une seule fois, au lieu d'avoir à interroger d'abord la table parente pour obtenir un ID, puis à interroger la table enfant avec cet ID. Par ailleurs, le fournisseur de contacts traite une requête sur une entité en une seule transaction, ce qui garantit que les données récupérées sont cohérents en interne.
Remarque:Une entité ne contient généralement pas toutes les colonnes des colonnes
table enfant. Si vous essayez de travailler avec un nom de colonne qui ne figure pas dans la liste des noms de colonne
constantes pour l'entité, vous obtenez une Exception
.
L'extrait de code suivant montre comment récupérer toutes les lignes de contact brutes d'un contact. L'extrait
fait partie d'une application plus vaste qui comporte deux activités, "main" et "détails". L'activité principale
affiche une liste de lignes de contact ; Lorsque l'utilisateur en sélectionne un, l'activité envoie son ID au détail
activité. L'activité "Détail" utilise le ContactsContract.Contacts.Entity
pour afficher toutes les lignes de données de tous les contacts bruts associés à l'élément sélectionné
contact.
Cet extrait est issu de la ligne "detail" activité:
Kotlin
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY ) // Initializes the loader identified by LOADER_ID. loaderManager.initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this // The context of the activity ) // Creates a new cursor adapter to attach to the list view cursorAdapter = SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0) // flags // Sets the ListView's backing adapter. rawContactList.adapter = cursorAdapter ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ val projection: Array<String> = arrayOf( ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE ) /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC" /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return CursorLoader( applicationContext, // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder // Sort by the raw contact ID. ) }
Java
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by LOADER_ID. getLoaderManager().initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this); // The context of the activity // Creates a new cursor adapter to attach to the list view cursorAdapter = new SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0); // flags // Sets the ListView's backing adapter. rawContactList.setAdapter(cursorAdapter); ... @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ String[] projection = { ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE }; /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC"; /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return new CursorLoader( getApplicationContext(), // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }
Une fois le chargement terminé, LoaderManager
invoque un rappel pour
onLoadFinished()
L'un des arguments entrants de cette méthode est un Cursor
avec les résultats de la requête. Dans votre propre application, vous pouvez obtenir les données de cette Cursor
pour les afficher ou les utiliser plus loin.
Modification par lot
Dans la mesure du possible, vous devez insérer, mettre à jour et supprimer des données dans Contacts Provider dans
"mode par lot" en créant une ArrayList
Objets ContentProviderOperation
et appels
applyBatch()
En effet,
le fournisseur de contacts effectue toutes les opérations
applyBatch()
en un seul
transaction, vos modifications ne laisseront jamais le référentiel de contacts dans un
de l'état. Une modification par lot facilite également l'insertion d'un contact brut et de ses données détaillées en même temps.
Remarque:Pour modifier un seul contact brut, envisagez d'envoyer un intent à l'application de gestion des contacts de l'appareil plutôt que de gérer la modification dans votre application. Cette procédure est décrite plus en détail dans la section Récupération et modification avec des intents
Points de rendement
Une modification par lot contenant un grand nombre d’opérations
peut bloquer d’autres processus,
ce qui nuit à l'expérience utilisateur globale. Pour organiser toutes les modifications que vous souhaitez
dans le moins de listes distinctes possible, tout en les empêchant
bloquant le système, définissez des points de rendement pour une ou plusieurs opérations.
Un point de rendement est un objet ContentProviderOperation
dont la valeur isYieldAllowed()
est définie sur true
. Lorsque le fournisseur de contacts rencontre un point de rendement, il suspend son travail pour laisser d'autres processus s'exécuter et ferme la transaction en cours. Lorsque le fournisseur redémarre, il poursuit l'opération suivante dans ArrayList
et démarre une nouvelle transaction.
Les points de rendement donnent lieu à plus d'une transaction par appel
applyBatch()
En raison de
vous devez définir un point de rendement pour la dernière opération d'un ensemble de lignes associées.
Par exemple, vous devez définir un point de rendement pour la dernière opération d'un ensemble qui ajoute une
lignes de contact brutes et les lignes de données associées, ou la dernière opération pour un ensemble de lignes liées
à un seul contact.
Les points de rendement sont également une unité d'opération atomique. Tous les accès entre deux points de rendement réussir ou échouer comme une seule unité. Si vous ne définissez aucun point de rendement, la plus petite opération atomique est l'ensemble du lot d'opérations. Si vous utilisez des points de rendement, des opérations de dégradation des performances du système, tout en garantissant qu'un sous-ensemble est atomique.
Références de modification d'arrière
Lorsque vous insérez une nouvelle ligne de contact brut et ses lignes de données associées en tant qu'ensemble d'objets ContentProviderOperation
, vous devez associer les lignes de données à la ligne de contact brut en insérant la valeur _ID
du contact brut en tant que valeur RAW_CONTACT_ID
. Toutefois,
La valeur n'est pas disponible lorsque vous créez le ContentProviderOperation
pour la ligne de données, car vous n'avez pas encore appliqué
ContentProviderOperation
pour la ligne de contact brute. Pour contourner ce problème, la classe ContentProviderOperation.Builder
dispose de la méthode withValueBackReference()
.
Cette méthode vous permet d'insérer ou de modifier une colonne à l'aide de la méthode
le résultat d'une opération précédente.
withValueBackReference()
comporte deux arguments:
-
key
- Clé d'une paire clé-valeur. La valeur de cet argument doit correspondre au nom d'une colonne du tableau que vous modifiez.
-
previousResult
-
Indice de base 0 d'une valeur dans le tableau d'objets
ContentProviderResult
deapplyBatch()
. En tant que les opérations par lot sont appliquées, le résultat de chaque opération est stocké dans un tableau intermédiaire de résultats. La valeurpreviousResult
correspond à l'index de l'un de ces résultats, qui est récupéré et stocké avec lekey
. Vous pouvez ainsi insérer un nouvel enregistrement de contact brut et récupérer sa valeur_ID
, puis créer une "référence arrière" à la valeur lorsque vous ajoutez une ligneContactsContract.Data
.L'ensemble du tableau de résultats est créé lors du premier appel de
applyBatch()
, avec une taille égale à celle de l'ArrayList
des objetsContentProviderOperation
que vous fournissez. Cependant, les éléments du tableau de résultats sont définis surnull
, et si vous essayez pour faire une référence arrière à un résultat pour une opération qui n'a pas encore été appliquée,withValueBackReference()
génère une erreurException
.
Les extraits suivants montrent comment insérer un contact brut et des données par lot. Ils incluent du code qui établit un point de rendement et utilise une référence arrière.
Le premier extrait récupère les données de contact à partir de l'UI. À ce stade, l'utilisateur a déjà sélectionné le compte pour lequel le nouveau contact brut doit être ajouté.
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
L'extrait suivant crée une opération pour insérer la ligne de contact brute dans la table ContactsContract.RawContacts
:
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
Ensuite, le code crée des lignes de données pour le nom à afficher, le numéro de téléphone et l'adresse e-mail.
Chaque objet de compilateur d'opération utilise withValueBackReference()
pour obtenir RAW_CONTACT_ID
. Les points de référence reviennent à l'objet ContentProviderResult
de la première opération, qui ajoute la ligne de contact brute et renvoie sa nouvelle valeur _ID
. Chaque ligne de données est donc automatiquement associée
RAW_CONTACT_ID
à la nouvelle ligne ContactsContract.RawContacts
à laquelle il appartient.
L'objet ContentProviderOperation.Builder
qui ajoute la ligne d'e-mail est signalé par withYieldAllowed()
, ce qui définit un point de rendement :
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
Le dernier extrait montre l'appel à applyBatch()
qui insère les nouvelles lignes de données et de contacts brutes.
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
Les opérations par lot permettent également d'implémenter un contrôle de simultanéité optimiste, une méthode permettant d'appliquer des transactions de modification sans avoir à verrouiller le dépôt sous-jacent. Pour utiliser cette méthode, appliquez la transaction, puis recherchez d'autres modifications peuvent avoir été effectuées en même temps. Si vous constatez qu'une modification incohérente s'est produite, annulez votre transaction et réessayez.
Le contrôle de la concurrence optimiste est utile pour un appareil mobile, où il n'y a qu'un seul utilisateur à la fois et où les accès simultanés à un dépôt de données sont rares. Étant donné que le verrouillage n'est pas utilisé, aucun temps n'est perdu à définir des verrous ni à attendre que d'autres transactions libèrent leurs verrous.
Pour utiliser le contrôle de simultanéité optimiste lors de la mise à jour d'un seul
ContactsContract.RawContacts
, procédez comme suit:
-
Récupérez la colonne
VERSION
du contact brut, ainsi que les autres données que vous récupérez. -
Créez un objet
ContentProviderOperation.Builder
adapté à appliquer une contrainte, à l'aide de la méthodenewAssertQuery(Uri)
Pour l'URI de contenu, utiliserRawContacts.CONTENT_URI
auquel est ajouté le_ID
du contact brut. -
Pour l'objet
ContentProviderOperation.Builder
, appelezwithValue()
pour comparer lesVERSION
par le numéro de version que vous venez de récupérer. -
Pour le même
ContentProviderOperation.Builder
, appelezwithExpectedCount()
pour garantir qu'une seule ligne est testée par cette assertion. -
Appelez
build()
pour créer l'objetContentProviderOperation
, puis ajoutez cet objet en tant que premier objet dans leArrayList
que vous transmettez àapplyBatch()
. - Appliquez la transaction par lot.
Si la ligne de contact brute est mise à jour par une autre opération entre le moment où vous lisez la ligne et celui où vous essayez de la modifier, l'assertion ContentProviderOperation
échoue et l'ensemble du lot d'opérations est annulé. Vous pourrez alors choisir de réessayer
ou effectuer une autre action.
L'extrait de code suivant montre comment créer une déclaration
ContentProviderOperation
après avoir interrogé un seul contact brut à l'aide de
un CursorLoader
:
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
Récupération et modification avec des intents
L'envoi d'un intent à l'application de gestion des contacts de l'appareil vous permet d'accéder à la liste Fournisseur indirectement. L'intent lance l'interface utilisateur de l'application Contacts de l'appareil, dans laquelle les utilisateurs peuvent faire du travail lié aux contacts. Avec ce type d'accès, les utilisateurs peuvent:
- Choisissez un contact dans une liste et renvoyez-le dans votre application pour la suite.
- Modifier les données d'un contact existant
- Insérer un nouveau contact brut pour l'un de ses comptes
- Supprimez un contact ou ses données.
Si l'utilisateur ajoute ou met à jour des données, vous pouvez d'abord les collecter et les envoyer en tant que de l'intent.
Lorsque vous utilisez des intents pour accéder au fournisseur de contacts via l'application Contacts de l'appareil, vous n'avez pas besoin d'écrire votre propre UI ni votre propre code pour accéder au fournisseur. Vous n'avez pas non plus à demander une autorisation en lecture ou en écriture au fournisseur. L'application Contacts de l'appareil peut l'autorisation de lecture pour un contact et, comme vous apportez des modifications au via une autre application, vous n'avez pas besoin d'autorisations en écriture.
Le processus général d'envoi d'un intent pour accéder à un fournisseur est décrit en détail dans le guide Principes de base des fournisseurs de contenu, dans la section "Accès aux données via les intents". L'action, le type MIME et les valeurs de données que vous utilisez pour les tâches disponibles sont résumés dans le tableau 4, tandis que les valeurs supplémentaires que vous pouvez utiliser avec putExtra()
sont listées dans la documentation de référence pour ContactsContract.Intents.Insert
:
Tableau 4. Intents du fournisseur de contacts
Tâche | Action | Données | Type MIME | Notes |
---|---|---|---|---|
Sélectionner un contact dans une liste | ACTION_PICK |
Au choix:
<ph type="x-smartling-placeholder">
|
Non utilisé |
Affiche une liste de contacts bruts ou une liste de données provenant d'un contact brut, en fonction de la
que vous fournissez.
Appeler
|
Insérer un nouveau contact brut | Insert.ACTION |
N/A |
RawContacts.CONTENT_TYPE est le type MIME d'un ensemble de contacts bruts.
|
Affiche l'écran Ajouter un contact de l'application Contacts de l'appareil. La
les valeurs supplémentaires que vous ajoutez à l'intent s'affichent. Si envoyé avec
startActivityForResult() ,
l'URI de contenu du contact brut nouvellement ajouté est renvoyé à l'API
onActivityResult()
de rappel dans l'argument Intent , dans
"données" . Pour obtenir la valeur, appelez getData() .
|
Modifier un contact | ACTION_EDIT |
CONTENT_LOOKUP_URI pour le contact. L'activité d'édition permettra à l'utilisateur de modifier les données associées
avec ce contact.
|
Contacts.CONTENT_ITEM_TYPE , un seul contact. |
Affiche l'écran Modifier le contact dans l'application Contacts. Les valeurs supplémentaires que vous ajoutez à l'intent sont affichées. Lorsque l'utilisateur clique sur OK pour enregistrer les modifications, votre activité revient au premier plan. |
Affichez un sélecteur permettant d'ajouter des données. | ACTION_INSERT_OR_EDIT |
N/A |
CONTENT_ITEM_TYPE
|
Cet intent affiche toujours l'écran de sélection de l'application Contacts. L'utilisateur peut :
sélectionnez un contact à modifier ou ajoutez-en un. L'écran de modification ou d'ajout s'affiche, selon le choix de l'utilisateur, et les données supplémentaires que vous transmettez dans l'intent s'affichent. Si votre application affiche des données de contact telles qu'une adresse e-mail ou un numéro de téléphone, utilisez cet intent pour permettre à l'utilisateur d'ajouter les données à un contact existant.
contact,
Remarque:Il n'est pas nécessaire d'envoyer une valeur "name" dans les extras de cet intent. car l'utilisateur choisit toujours un nom existant ou en ajoute un nouveau. De plus, si vous envoyez un nom et que l'utilisateur choisit de le modifier, l'application Contacts affiche le nom que vous envoyez, en écrasant la valeur précédente. Si l'utilisateur n'a pas notez que la modification est enregistrée et l'ancienne valeur est perdue. |
L'application Contacts de l'appareil ne vous permet pas de supprimer un contact brut ni aucune de ses données à l'aide d'un intent. Pour supprimer un contact brut, utilisez plutôt ContentResolver.delete()
ou ContentProviderOperation.newDelete()
.
L'extrait de code suivant montre comment créer et envoyer un intent qui insère un nouveau contact brut et des données :
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
Intégrité des données
Parce que le référentiel de contacts contient des données importantes et sensibles que les utilisateurs s'attendent à voir correctes et à jour, le fournisseur de contacts dispose de règles bien définies pour l'intégrité des données. Il est de votre responsabilité de vous conformer à ces règles lorsque vous modifiez les données de contact. Voici les règles importantes :
-
Ajoutez toujours une ligne
ContactsContract.CommonDataKinds.StructuredName
pour chaque ligneContactsContract.RawContacts
que vous ajoutez. -
Une ligne
ContactsContract.RawContacts
sansContactsContract.CommonDataKinds.StructuredName
ligne dans La tableContactsContract.Data
peut causer des problèmes pendant l'agrégation. -
Associez toujours les nouvelles lignes
ContactsContract.Data
à leur ligneContactsContract.RawContacts
parente. -
Une ligne
ContactsContract.Data
qui n'est pas associée à unContactsContract.RawContacts
ne sera pas visible dans l'application Contacts de l'appareil et peut entraîner des problèmes avec les adaptateurs de synchronisation. - Modifiez uniquement les données des contacts bruts dont vous êtes le propriétaire.
- N'oubliez pas que le fournisseur de contacts gère généralement les données de plusieurs types de comptes/services en ligne différents. Vous devez vous assurer que votre application ne modifie ni ne supprime que les données des lignes qui vous appartiennent, et qu'elle n'insère que des données avec un type et un nom de compte que vous contrôlez.
-
Utilisez toujours les constantes définies dans
ContactsContract
et ses sous-classes pour les autorités, les URI de contenu, les chemins d'URI, les noms de colonnes, les types MIME et les valeursTYPE
. - L'utilisation de ces constantes vous permet d'éviter les erreurs. Vous recevrez aussi une notification avec le compilateur si l'une des constantes est obsolète.
Lignes de données personnalisées
En créant et en utilisant vos propres types MIME personnalisés, vous pouvez insérer, modifier, supprimer et récupérer vos propres lignes de données dans le tableau ContactsContract.Data
. Vos lignes sont limitées à l'utilisation de la colonne définie dans ContactsContract.DataColumns
, bien que vous puissiez mapper vos propres noms de colonnes spécifiques au type aux noms de colonnes par défaut. Dans l'application Contacts de l'appareil,
les données de vos lignes s'affichent, mais ne peuvent être ni modifiées, ni supprimées, et les utilisateurs ne peuvent pas ajouter
des données supplémentaires. Pour permettre aux utilisateurs de modifier vos lignes de données personnalisées, vous devez fournir une activité d'éditeur dans votre propre application.
Pour afficher vos données personnalisées, fournissez un fichier contacts.xml
contenant un
l'élément <ContactsAccountType>
et un ou plusieurs de ses
<ContactsDataKind>
éléments enfants. Ce point est décrit plus en détail dans la section <ContactsDataKind> element
.
Pour en savoir plus sur les types MIME personnalisés, consultez le <ph type="x-smartling-placeholder"></ph> Créer un guide pour les fournisseurs de contenu
Adaptateurs de synchronisation Contacts Provider
Le fournisseur de contacts est spécialement conçu pour gérer la synchronisation des données de contact entre un appareil et un service en ligne. Cela permet aux utilisateurs de télécharger des données existantes sur un nouvel appareil et d'importer des données existantes dans un nouveau compte. La synchronisation garantit également que les utilisateurs disposent des dernières données à portée de main, quelle que soit la source des ajouts et des modifications. Un autre avantage de la synchronisation est qu'elle facilite les données des contacts disponibles même lorsque l'appareil n'est pas connecté au réseau.
Bien que vous puissiez implémenter la synchronisation de différentes manières, le système Android fournit un framework de synchronisation de plug-ins qui automatise les tâches suivantes :
- Vérification de la disponibilité du réseau.
- Planification et exécution de la synchronisation en fonction des préférences de l'utilisateur
- Redémarrer les synchronisations qui ont été arrêtées.
Pour utiliser ce framework, vous devez fournir un plug-in d'adaptateur de synchronisation. Chaque adaptateur de synchronisation est propre à un service et à un fournisseur de contenu, mais peut gérer plusieurs noms de compte pour le même service. Le framework autorise également plusieurs adaptateurs de synchronisation pour le même service et le même fournisseur.
Synchroniser les classes et les fichiers des adaptateurs
Vous implémentez un adaptateur de synchronisation en tant que sous-classe de
AbstractThreadedSyncAdapter
et l'installer dans un environnement Android
application. Le système apprend l'existence de l'adaptateur de synchronisation à partir des éléments de votre application
le fichier manifeste, et à partir d'un fichier XML spécial
versé par le fichier manifeste. Le fichier XML définit
le type de compte pour le service en ligne et l'autorité pour le fournisseur de contenu, qui, ensemble,
identifier l'adaptateur de manière unique. L'adaptateur de synchronisation ne devient actif que lorsque l'utilisateur ajoute un
prend en compte le type de compte de l'adaptateur de synchronisation et active la synchronisation du contenu
fournisseur avec lequel l'adaptateur de synchronisation se synchronise. À ce stade, le système commence à gérer l'adaptateur, en l'appelant si nécessaire pour synchroniser le fournisseur de contenu et le serveur.
Remarque:L'utilisation d'un type de compte dans l'identification de l'adaptateur de synchronisation permet
le système doit détecter et regrouper les adaptateurs de synchronisation qui accèdent à différents services
même organisation. Par exemple, les adaptateurs de synchronisation des services en ligne de Google ont tous le même
Type de compte com.google
. Lorsque les utilisateurs ajoutent un compte Google à leurs appareils, tous les adaptateurs de synchronisation installés pour les services Google sont listés ensemble. Chaque adaptateur de synchronisation listé se synchronise avec un fournisseur de contenu différent sur l'appareil.
Étant donné que la plupart des services exigent que les utilisateurs valident leur identité avant d'accéder aux données, le système Android propose un framework d'authentification semblable au framework d'adaptateur de synchronisation et souvent utilisé en conjonction avec celui-ci. Le framework d'authentification utilise des authentificateurs de plug-in qui sont des sous-classes de AbstractAccountAuthenticator
. Un authentificateur vérifie
l'identité de l'utilisateur lors des étapes suivantes:
- Collecte le nom, le mot de passe ou des informations similaires de l'utilisateur (ses identifiants).
- Envoie les identifiants au service
- Il examine la réponse du service.
Si le service accepte les identifiants, l'authentificateur peut les stocker pour une utilisation ultérieure. Grâce au framework d'authentification des plug-ins,
AccountManager
peut fournir l'accès à n'importe quel jeton d'authentification d'un authentificateur
prend en charge et choisit d'exposer, comme les jetons d'authentification OAuth2.
Bien que l'authentification ne soit pas requise, la plupart des services de gestion des contacts l'utilisent. Toutefois, vous n'êtes pas obligé d'utiliser le framework d'authentification Android pour vous authentifier.
Implémentation de l'adaptateur de synchronisation
Pour implémenter un adaptateur de synchronisation pour le fournisseur de contacts, commencez par créer une application Android contenant les éléments suivants :
-
Un composant
Service
qui répond aux requêtes du système pour s'associer à l'adaptateur de synchronisation. -
Lorsque le système souhaite exécuter une synchronisation, il appelle la méthode
onBind()
du service pour obtenir unIBinder
pour l'adaptateur de synchronisation. Cela permet au système d'effectuer les appels inter-processus aux méthodes de l'adaptateur. -
L'adaptateur de synchronisation réel, implémenté comme une sous-classe concrète de
AbstractThreadedSyncAdapter
-
Cette classe se charge de télécharger les données à partir du serveur et d'importer les données à partir du
et résoudre les conflits. Le travail principal de l'adaptateur est effectué dans la méthode
onPerformSync()
. Cette classe doit être instanciée en tant que singleton. -
Une sous-classe de
Application
. -
Cette classe sert de fabrique pour le singleton de l'adaptateur de synchronisation. Utilisez les
onCreate()
pour instancier l'adaptateur de synchronisation. fournissent un "getter" statique pour renvoyer le singleton à laonBind()
de l'adaptateur de synchronisation Google Cloud. -
Facultatif : composant
Service
qui répond aux requêtes du système pour l'authentification des utilisateurs. -
AccountManager
démarre ce service pour commencer l'authentification processus. La méthodeonCreate()
du service instancie un objet authentificateur. Lorsque le système veut authentifier un compte d'utilisateur pour l'adaptateur de synchronisation de l'application, celui-ci appelleonBind()
pour obtenir uneIBinder
pour l'authentificateur. Cela permet au système d'effectuer des appels inter-processus aux méthodes de l'authentificateur. -
Facultatif:sous-classe concrète de
AbstractAccountAuthenticator
qui gère les requêtes pour l'authentification unique. -
Cette classe fournit des méthodes que
AccountManager
appelle pour authentifier les identifiants de l'utilisateur auprès du serveur. Les détails processus d'authentification varient considérablement, en fonction de la technologie de serveur utilisée. Vous devez reportez-vous à la documentation de votre logiciel serveur pour en savoir plus sur l'authentification. - Fichiers XML qui définissent l'adaptateur de synchronisation et l'authentificateur dans le système.
-
Les composants du service d'adaptateur de synchronisation et du service d'authentification décrits précédemment
défini dans
<service>
dans le fichier manifeste de l'application. Ces éléments contiennent des éléments enfants<meta-data>
qui fournissent des données spécifiques au système :-
L'élément
<meta-data>
du service d'adaptateur de synchronisation pointe vers le fichier XMLres/xml/syncadapter.xml
. À son tour, ce fichier spécifie un URI pour le service Web qui sera synchronisé avec Contacts Provider et un type de compte pour le service Web. -
Facultatif : L'élément
<meta-data>
de l'authentificateur pointe vers le fichier XMLres/xml/authenticator.xml
. Ce fichier spécifie quant à lui compatible avec cet authentificateur, ainsi que les ressources d'UI lors du processus d'authentification. Le type de compte spécifié dans ce doit être identique au type de compte spécifié pour la synchronisation. adaptateur secteur.
-
L'élément
Données de flux sur les réseaux sociaux
Les tables android.provider.ContactsContract.StreamItems et android.provider.ContactsContract.StreamItemPhotos gèrent les données entrantes des réseaux sociaux. Vous pouvez écrire un adaptateur de synchronisation qui ajoute des données de flux à partir de votre propre réseau à ces tables, ou vous pouvez lire des données de flux à partir de ces tables et les afficher dans votre propre application, ou les deux. Grâce à ces fonctionnalités, vos réseaux sociaux les services et applications peuvent être intégrés dans l'expérience de réseau social d'Android.
Texte du flux sur les réseaux sociaux
Les éléments de flux sont toujours associés à un contact brut. La
android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID renvoie vers le
Valeur _ID
pour le contact brut. Le type de compte et le nom du compte du contact brut sont également stockés dans la ligne de l'élément de flux.
Stockez les données de votre flux dans les colonnes suivantes:
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
- Obligatoire. Type de compte de l'utilisateur pour le contact brut associé à cet élément de flux. N'oubliez pas de définir cette valeur lorsque vous insérez un élément de flux.
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
- Obligatoire. Nom du compte utilisateur pour le contact brut associé à l'élément de flux. N'oubliez pas de définir cette valeur lorsque vous insérez un élément de flux.
- Colonnes d'identifiants
-
Obligatoire. Vous devez insérer les colonnes d'identifiants suivantes lorsque vous
insérer un élément de flux:
<ph type="x-smartling-placeholder">
- </ph>
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID : valeur android.provider.BaseColumns#_ID du contact auquel cet élément de flux est associé.
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY : android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY de la valeur contact auquel cet élément de flux est associé.
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID : Valeur android.provider.BaseColumns#_ID du contact brut que ce flux auquel l'élément est associé.
- android.provider.ContactsContract.StreamItemsColumns#COMMENTS
- (Facultatif) Stocke des informations récapitulatives que vous pouvez afficher au début d'un élément de flux.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
Texte de l'élément de flux (contenu publié par la source de l'élément)
ou la description d'une action
ayant généré l'élément de flux. Cette colonne peut contenir tout formatage et toute image de ressource intégrée pouvant être affichés par
fromHtml()
. Le fournisseur peut tronquer ou ellipsize contenu long, mais essaiera d’éviter de casser les balises. - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- Chaîne de texte contenant l'heure à laquelle l'élément de flux a été inséré ou mis à jour, au format de millisecondes depuis l'epoch. Les applications qui insèrent ou mettent à jour des éléments de flux sont responsable de la gestion de cette colonne ; elle n'est pas automatiquement gérée Fournisseur de contacts.
Pour afficher les informations d'identification de vos éléments de flux, utilisez l'événement android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL et android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE pour créer un lien vers des ressources dans votre application.
La table android.provider.ContactsContract.StreamItems contient également les colonnes android.provider.ContactsContract.StreamItemsColumns#SYNC1 à android.provider.ContactsContract.StreamItemsColumns#SYNC4, réservées à l'usage exclusif des adaptateurs de synchronisation.
Photos du flux sur les réseaux sociaux
La table android.provider.ContactsContract.StreamItemPhotos stocke les photos associées
avec un élément de flux. La colonne android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID de la table fait référence aux valeurs de la colonne _ID
de la table android.provider.ContactsContract.StreamItems. Les références de photos sont stockées dans
tableau dans ces colonnes:
- Colonne android.provider.ContactsContract.StreamItemPhotos#PHOTO (un BLOB).
- Représentation binaire de la photo, redimensionnée par le fournisseur pour le stockage et l'affichage. Cette colonne est disponible pour assurer la rétrocompatibilité avec les versions précédentes de Contacts. Fournisseur qui l'a utilisé pour stocker des photos. Toutefois, dans la version actuelle, vous ne devez pas utiliser cette colonne pour stocker des photos. Utilisez plutôt android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID ou android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (les deux étant décrits dans les points suivants) pour stocker des photos dans un fichier. Cette colonne contient désormais une vignette de la photo, qui est disponible à la lecture.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
Identifiant numérique d'une photo pour un contact brut. Ajoutez cette valeur à la constante
DisplayPhoto.CONTENT_URI
pour obtenir un URI de contenu pointant vers un seul fichier photo, puis appelezopenAssetFileDescriptor()
pour obtenir un gestionnaire du fichier photo. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
URI de contenu pointant directement vers le fichier photo de la photo représentée par cette ligne.
Appelez
openAssetFileDescriptor()
avec cet URI pour obtenir un handle vers le fichier photo.
Utiliser les tableaux des flux de réseaux sociaux
Ces tables fonctionnent de la même manière que les autres tables principales du fournisseur de contacts, à l'exception des points suivants :
- Ces tables nécessitent des autorisations d'accès supplémentaires. Pour les lire, votre application doit disposer de l'autorisation android.Manifest.permission#READ_SOCIAL_STREAM. Pour les modifier, votre application doit disposer de l'autorisation android.Manifest.permission#WRITE_SOCIAL_STREAM.
-
Pour la table android.provider.ContactsContract.StreamItems, le nombre de lignes stockées pour chaque contact brut est limité. Une fois cette limite atteinte,
le fournisseur de contacts fait de la place pour de nouvelles lignes d'éléments de flux en supprimant automatiquement
les lignes comportant la plus ancienne
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. Pour obtenir la limite, envoyez une requête à l'URI de contenu android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. Vous pouvez laisser tous les arguments autres que l'URI de contenu définis sur
null
. La requête renvoie un Cursor contenant une seule ligne, avec la colonne unique android.provider.ContactsContract.StreamItems#MAX_ITEMS.
La classe android.provider.ContactsContract.StreamItems.StreamItemPhotos définit une Sous-tableau d'android.provider.ContactsContract.StreamItemPhotos contenant la photo pour un même élément de flux.
Interactions avec les flux sur les réseaux sociaux
Les données de flux de réseaux sociaux gérées par le fournisseur de contacts, conjointement avec le l'application Contacts de votre appareil, offre un moyen efficace de connecter votre système de réseau social avec vos contacts existants. Les fonctionnalités suivantes sont disponibles:
- En synchronisant votre service de réseau social avec le fournisseur de contacts à l'aide d'une fonction de synchronisation adaptateur, vous pouvez récupérer l'activité récente des contacts d'un utilisateur et la stocker dans android.provider.ContactsContract.StreamItems et android.provider.ContactsContract.StreamItemPhotos pour une utilisation ultérieure.
- En plus de la synchronisation régulière, vous pouvez déclencher votre adaptateur de synchronisation pour récupérer des données supplémentaires lorsque l'utilisateur sélectionne un contact à afficher. Cela permet à votre adaptateur de synchronisation de récupérer les photos haute résolution et les éléments de flux les plus récents pour le contact.
- En enregistrant une notification dans l'application Contacts de l'appareil et dans l'application Contacts vous pouvez recevoir un intent lorsqu'un contact est consulté, et à ce stade mettre à jour l'état du contact à partir de votre service. Cette approche peut être plus rapide et utiliser moins de bande passante qu'une synchronisation complète avec un adaptateur de synchronisation.
- Les utilisateurs peuvent ajouter un contact à votre service de réseau social tout en le consultant dans l'application Contacts de l'appareil. Vous activez cette option avec l'option "Inviter un contact" fonctionnalité, que vous activez en combinant une activité qui ajoute un contact existant à votre réseau, et un fichier XML qui fournit l'application de contacts de l'appareil et le Contact Provider avec les détails de votre application.
La synchronisation régulière des éléments de flux avec Contacts Provider s'effectue de la même manière que ou effectuer d'autres synchronisations. Pour en savoir plus sur la synchronisation, consultez la section Adaptateurs de synchronisation du fournisseur de contacts. L'enregistrement des notifications et inviter des contacts sont abordés dans les deux sections suivantes.
S'inscrire pour gérer les vues de réseaux sociaux
Pour enregistrer votre adaptateur de synchronisation afin de recevoir des notifications lorsque l'utilisateur consulte un contact géré par votre adaptateur de synchronisation:
-
Créez un fichier nommé
contacts.xml
dans le répertoireres/xml/
de votre projet. Si vous disposez déjà de ce fichier, vous pouvez ignorer cette étape. -
Dans ce fichier, ajoutez l'élément
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. Si cet élément existe déjà, vous pouvez ignorer cette étape. -
Pour enregistrer un service qui est averti lorsque l'utilisateur ouvre la page d'informations d'un contact dans l'application Contacts de l'appareil, ajoutez l'attribut
viewContactNotifyService="serviceclass"
à l'élément, oùserviceclass
est le nom de classe complet du service qui doit recevoir l'intent de l'application Contacts de l'appareil. Pour le service de notification, utilisez une classe qui étendIntentService
pour permettre au service de recevoir des intents. Les données de l'intent entrant contiennent l'URI de contenu du contact brut sur lequel l'utilisateur a cliqué. À partir du service de notification, vous pouvez vous associer à votre adaptateur de synchronisation, puis l'appeler pour mettre à jour les données du contact brut.
Pour enregistrer une activité à appeler lorsque l'utilisateur clique sur un élément de flux, une photo ou les deux:
-
Créez un fichier nommé
contacts.xml
dans le répertoireres/xml/
de votre projet. Si vous disposez déjà de ce fichier, vous pouvez ignorer cette étape. -
Dans ce fichier, ajoutez l'élément
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
Si cet élément existe déjà, vous pouvez ignorer cette étape. -
Pour enregistrer l'une de vos activités afin de gérer le clic de l'utilisateur sur un élément de flux dans l'application Contacts de l'appareil, ajoutez l'attribut
viewStreamItemActivity="activityclass"
à l'élément, oùactivityclass
est le nom de classe complet de l'activité qui doit recevoir l'intent de l'application Contacts de l'appareil. -
Pour enregistrer l'une de vos activités afin de gérer les clics de l'utilisateur sur une photo de flux dans la
l'application Contacts de l'appareil, ajoutez l'attribut
viewStreamItemPhotoActivity="activityclass"
à l'élément, oùactivityclass
est le nom de classe complet de l'activité. qui doit recevoir l'intent de l'application de contacts de l'appareil.
L'élément <ContactsAccountType>
est décrit plus en détail dans la section Élément <ContactsAccountType>.
L'intent entrant contient l'URI de contenu de l'élément ou de la photo sur lesquels l'utilisateur a cliqué. Pour avoir des activités distinctes pour les articles textuels et les photos, utilisez les deux attributs dans le même fichier.
Interagir avec votre service de réseautage social
Les utilisateurs n'ont pas besoin de quitter l'application Contacts de l'appareil pour inviter un contact à rejoindre votre site de réseautage social. Vous pouvez plutôt demander à l'application Contacts de l'appareil d'envoyer un intent pour inviter le contact à l'une de vos activités. Pour configurer une expérience supervisée :
-
Créez un fichier nommé
contacts.xml
dans le répertoireres/xml/
de votre projet. Si vous disposez déjà de ce fichier, vous pouvez ignorer cette étape. -
Dans ce fichier, ajoutez l'élément
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
Si cet élément existe déjà, vous pouvez ignorer cette étape. -
Ajoutez les attributs suivants :
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
correspond au nom de classe complet de l'activité qui doit recevoir l'intent.invite_action_label
est une chaîne de texte qui s'affiche dans le menu Ajouter une connexion dans la l'application Contacts de votre appareil.
Remarque : ContactsSource
est un nom de balise obsolète pour ContactsAccountType
.
Documentation de référence sur contacts.xml
Le fichier contacts.xml
contient des éléments XML qui contrôlent l'interaction de votre adaptateur de synchronisation et de votre application avec l'application Contacts et le fournisseur de contacts. Ces éléments sont décrits dans les sections suivantes.
Élément <ContactsAccountType>
L'élément <ContactsAccountType>
contrôle l'interaction de votre
avec l'application Contacts. Elle utilise la syntaxe suivante:
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android" inviteContactActivity="activity_name" inviteContactActionLabel="invite_command_text" viewContactNotifyService="view_notify_service" viewGroupActivity="group_view_activity" viewGroupActionLabel="group_action_text" viewStreamItemActivity="viewstream_activity_name" viewStreamItemPhotoActivity="viewphotostream_activity_name">
contenu dans :
res/xml/contacts.xml
peut contenir:
<ContactsDataKind>
Description :
Déclarer des composants Android et des libellés d'interface utilisateur permettant aux utilisateurs d'inviter l'un de leurs contacts à rejoindre un réseau social, de les informer lorsqu'un de leurs flux de réseau social est mis à jour, etc.
Notez que le préfixe d'attribut android:
n'est pas nécessaire pour les attributs de <ContactsAccountType>
.
Attributs:
inviteContactActivity
- Nom de classe complet de l'activité de votre application que vous souhaitez activer lorsque l'utilisateur sélectionne Ajouter une connexion dans l'application Contacts de l'appareil.
inviteContactActionLabel
-
Chaîne de texte affichée pour l'activité spécifiée dans
inviteContactActivity
, dans le menu Ajouter une connexion. Par exemple, vous pouvez utiliser la chaîne "Suivre dans mon réseau". Vous pouvez utiliser un identifiant de ressource de chaîne pour ce libellé. viewContactNotifyService
- Nom de classe complet d'un service de votre application qui doit recevoir des notifications lorsque l'utilisateur consulte un contact. Cette notification est envoyée par l'application de contacts de l'appareil. Elle permet à votre application de différer les opérations gourmandes en données jusqu'à ce qu'elles soient nécessaires. Par exemple, votre application peut répondre à cette notification en lisant et en affichant la photo haute résolution du contact et les éléments les plus récents de son flux de réseau social. Cette fonctionnalité est décrite plus en détail dans la section Interactions avec les flux sur les réseaux sociaux :
viewGroupActivity
- Nom de classe complet d'une activité de votre application pouvant afficher des informations de groupe. Lorsque l'utilisateur clique sur le libellé de groupe dans l'application Contacts de l'appareil, l'UI de cette activité s'affiche.
viewGroupActionLabel
-
Libellé affiché par l'application Contacts pour un contrôle d'interface utilisateur permettant à l'utilisateur d'afficher des groupes dans votre application.
Un identifiant de ressource de chaîne est autorisé pour cet attribut.
viewStreamItemActivity
- Nom de classe complet d'une activité dans votre application que l'appareil L'application de gestion des contacts se lance lorsque l'utilisateur clique sur un élément de flux pour un contact brut.
viewStreamItemPhotoActivity
- Nom de classe complet d'une activité de votre application que l'application Contacts de l'appareil lance lorsque l'utilisateur clique sur une photo dans l'élément de flux pour un contact brut.
<ContactsDataKind (Genre de données de contacts) élément
L'élément <ContactsDataKind>
contrôle l'affichage des
des lignes de données personnalisées dans l'interface utilisateur de l'application Contacts. Il utilise la syntaxe suivante :
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
contenu dans :
<ContactsAccountType>
Description :
Utilisez cet élément pour que l'application Contacts affiche le contenu d'une ligne de données personnalisée au format
une partie des détails
d'un contact brut. Chaque élément enfant <ContactsDataKind>
de <ContactsAccountType>
représente un type de ligne de données personnalisées que vous synchronisez
l'adaptateur est ajouté à la table ContactsContract.Data
. Ajoutez un élément <ContactsDataKind>
pour chaque type MIME personnalisé que vous utilisez. Vous n'avez pas
pour ajouter l'élément si vous disposez d'une ligne de données personnalisée pour laquelle vous ne souhaitez pas afficher de données.
Attributs:
android:mimeType
-
Le type MIME personnalisé que vous avez défini pour l'un de vos types de lignes de données personnalisées dans le tableau
ContactsContract.Data
. Par exemple, la valeurvnd.android.cursor.item/vnd.example.locationstatus
peut être un type MIME personnalisé pour une ligne de données qui enregistre la dernière position connue d'un contact. android:icon
- Une ressource drawable Android que l'application Contacts affiche à côté de vos données. Utilisez-le pour indiquer à l'utilisateur que les données proviennent de votre service.
android:summaryColumn
- Nom de la colonne de la première des deux valeurs extraites de la ligne de données. La valeur s'affiche sur la première ligne de l'entrée de cette ligne de données. La première ligne est destinée à servir de résumé des données, mais elle est facultative. Voir aussi android:detailColumn
android:detailColumn
-
Nom de la colonne pour la deuxième des deux valeurs récupérées à partir de la ligne de données. La valeur s'affiche sur la deuxième ligne de l'entrée de cette ligne de données. Voir aussi
android:summaryColumn
Fonctionnalités supplémentaires de Contacts Provider
En plus des fonctionnalités principales décrites dans les sections précédentes, le fournisseur de contacts propose fonctions utiles suivantes pour exploiter les données de contacts:
- Groupes de contacts
- Fonctionnalités photo
Groupes de contacts
Le fournisseur de contacts peut éventuellement étiqueter des collections de contacts associés avec des données de groupe. Si le serveur associé à un compte d'utilisateur
souhaite gérer les groupes, l'adaptateur de synchronisation du type de compte du compte doit transférer
regroupe les données entre le fournisseur de contacts et le serveur. Lorsque les utilisateurs ajoutent un contact au serveur, puis le placent dans un nouveau groupe, l'adaptateur de synchronisation doit ajouter le nouveau groupe au tableau ContactsContract.Groups
. Le ou les groupes d'un ou de plusieurs
auquel le contact appartient sont stockés dans la table ContactsContract.Data
, en utilisant
le type MIME ContactsContract.CommonDataKinds.GroupMembership
.
Si vous concevez un adaptateur de synchronisation
qui ajoutera des données de contact brutes
au fournisseur de contacts et que vous n'utilisez pas de groupes, vous devez indiquer au
Fournisseur pour rendre vos données visibles. Dans le code exécuté lorsqu'un utilisateur ajoute un compte
sur l'appareil, mettez à jour le ContactsContract.Settings
que le fournisseur de contacts ajoute pour le compte. Dans cette ligne, définissez la valeur de la colonne Settings.UNGROUPED_VISIBLE
sur 1. Dans ce cas, Contacts Provider
rendre visibles les données de vos contacts, même si vous n'utilisez pas de groupes.
Photos des contacts
La table ContactsContract.Data
stocke les photos sous forme de lignes avec le type MIME
Photo.CONTENT_ITEM_TYPE
La ligne
La colonne CONTACT_ID
est associée à
Colonne _ID
du contact brut auquel il appartient.
La classe ContactsContract.Contacts.Photo
définit un sous-tableau de
ContactsContract.Contacts
contenant des informations sur la photo d'un contact
photo principale, qui est la photo principale du contact brut principal du contact. De même, la classe ContactsContract.RawContacts.DisplayPhoto
définit une sous-table de ContactsContract.RawContacts
contenant des informations sur la photo principale d'un contact brut.
La documentation de référence pour ContactsContract.Contacts.Photo
et
ContactsContract.RawContacts.DisplayPhoto
contiennent des exemples de
récupération des informations sur les photos. Il n'existe aucune classe pratique pour récupérer la vignette principale d'un contact brut, mais vous pouvez envoyer une requête à la table ContactsContract.Data
, en sélectionnant le _ID
, le Photo.CONTENT_ITEM_TYPE
et la colonne IS_PRIMARY
du contact brut pour trouver la ligne de photo principale du contact brut.
Les données de flux de réseaux sociaux concernant une personne peuvent également inclure des photos. Celles-ci sont stockées dans android.provider.ContactsContract.StreamItemPhotos, décrite plus en détail détail dans la section Photos du flux de réseau social.