J'essaie d'implémenter le modèle d'adaptateur Content-Provider-Sync comme indiqué dans Google IO - diapositive 26. Mon fournisseur de contenu fonctionne et ma synchronisation fonctionne lorsque je la déclenche à partir de l'application Dev Tools Sync Tester, mais lorsque j'appelle ContentResolver. requestSync (compte, autorité, bundle) depuis mon ContentProvider, ma synchronisation n'est jamais déclenchée.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
Edit - extrait de manifeste ajouté Mon manifeste xml contient:
<service
android:name=".sync.SyncService"
android:exported="true">
<intent-filter>
<action
android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
--Éditer
Mon syncadapter.xml associé à mon service de synchronisation contient:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="AUTHORITY"
android:accountType="myaccounttype"
android:supportsUploading="true"
/>
Je ne sais pas quel autre code serait utile. Le compte passé à requestSync est de "myaccounttype" et l'AUTORITÉ passée à l'appel correspond à mon adaptateur syc xml.
ContentResolver.requestSync est-il le moyen correct de demander une synchronisation? Il semble que l'outil de test de synchronisation se lie directement au service et appelle la synchronisation, mais cela semble aller à l'encontre de l'objectif de l'intégration avec l'architecture de synchronisation.
Si c'est la bonne façon de demander une synchronisation, pourquoi le testeur de synchronisation fonctionnerait-il, mais pas mon appel à ContentResolver.requestSync? Dois-je passer quelque chose dans le bundle?
Je teste dans l'émulateur sur des appareils exécutant 2.1 et 2.2.
android:process=":sync"
du service de synchronisation laisse le débogueur atteindre les points de bec. Le service de synchronisation lui-même fonctionnait avant cela, car je pouvais voir les messages du journal de laonPerformSync
méthode au nom d'un autre processus.Réponses:
L'appel
requestSync()
ne fonctionnera que sur une paire {Account, ContentAuthority} connue du système. Votre application doit suivre un certain nombre d'étapes pour indiquer à Android que vous êtes capable de synchroniser un type de contenu spécifique à l'aide d'un type de compte spécifique. Il le fait dans le fichier AndroidManifest.1. Informez Android que votre package d'application permet la synchronisation
Tout d'abord, dans AndroidManifest.xml, vous devez déclarer que vous disposez d'un service de synchronisation:
L'attribut name de la
<service>
balise est le nom de votre classe pour connecter la synchronisation ... J'en parlerai dans une seconde.Le paramètre exporté sur true le rend visible par les autres composants (nécessaire, vous
ContentResolver
pouvez donc l' appeler).Le filtre d'intention lui permet d'attraper un intent demandant une synchronisation. (Cela
Intent
vient duContentResolver
moment où vous appelezContentResolver.requestSync()
ou des méthodes de planification associées.)L'
<meta-data>
étiquette sera discutée ci-dessous.2. Fournissez à Android un service utilisé pour trouver votre SyncAdapter
Donc la classe elle-même ... Voici un exemple:
Votre classe doit étendre
Service
ou l'une de ses sous-classes, doit implémenterpublic IBinder onBind(Intent)
et doit renvoyer aSyncAdapterBinder
quand elle est appelée ... Vous avez besoin d'une variable de typeAbstractThreadedSyncAdapter
. Donc, comme vous pouvez le voir, c'est à peu près tout dans cette classe. La seule raison pour laquelle il existe est de fournir un service, qui offre une interface standard pour Android pour interroger votre classe sur ce que vousSyncAdapter
êtes.3. Fournissez un
class SyncAdapter
pour effectuer réellement la synchronisation.mySyncAdapter est l'endroit où la vraie logique de synchronisation elle-même est stockée. Sa
onPerformSync()
méthode est appelée au moment de la synchronisation. Je suppose que vous l'avez déjà en place.4. Établir une liaison entre un type de compte et une autorité de contenu
En regardant à nouveau AndroidManifest, cette
<meta-data>
balise étrange dans notre service est l'élément clé qui établit la liaison entre un ContentAuthority et un compte. Il fait référence en externe à un autre fichier xml (appelez-le comme vous le souhaitez, quelque chose de pertinent pour votre application.) Regardons sync_myapp.xml:Ok, alors qu'est-ce que ça fait? Il indique à Android que l'adaptateur de synchronisation que nous avons défini (la classe qui a été appelée dans l'élément de nom de la
<service>
balise qui comprend la<meta-data>
balise qui fait référence à ce fichier ...) synchronisera les contacts à l'aide d'un compte de style com.google.Toutes vos chaînes contentAuthority doivent toutes correspondre et correspondre à ce que vous synchronisez - Il doit s'agir d'une chaîne que vous définissez, si vous créez votre propre base de données, ou vous devez utiliser des chaînes d'appareils existantes si vous synchronisez types de données (comme les contacts ou les événements de calendrier ou tout le reste.) Ce qui précède ("com.android.contacts") se trouve être la chaîne ContentAuthority pour les données de type de contacts (surprise, surprise.)
accountType doit également correspondre à l'un de ces types de comptes connus qui sont déjà saisis, ou il doit correspondre à celui que vous créez (cela implique la création d'une sous-classe de AccountAuthenticator pour obtenir l'authentification sur votre serveur ... Vaut un article, lui-même.) Encore une fois, "com.google" est la chaîne définie identifiant ... les informations d'identification du compte de style google.com (encore une fois, cela ne devrait pas être une surprise.)
5. Activer la synchronisation sur une paire Compte / ContentAuthority donnée
Enfin, la synchronisation doit être activée. Vous pouvez le faire dans la page Comptes et synchronisation du panneau de configuration en accédant à votre application et en cochant la case à côté de votre application dans le compte correspondant. Vous pouvez également le faire dans un code de configuration dans votre application:
Pour que la synchronisation se produise, votre paire compte / autorité doit être activée pour la synchronisation (comme ci-dessus) et l'indicateur global de synchronisation globale sur le système doit être défini, et l'appareil doit disposer d'une connectivité réseau.
Si la synchronisation de votre compte / autorité ou la synchronisation globale sont désactivées, l'appel de RequestSync () a un effet - Il définit un indicateur indiquant que la synchronisation a été demandée et sera effectuée dès que la synchronisation sera activée.
De plus, par mgv , définir
ContentResolver.SYNC_EXTRAS_MANUAL
sur true dans le bundle extras de votre requestSync demandera à android de forcer une synchronisation même si la synchronisation globale est désactivée (soyez respectueux de votre utilisateur ici!)Enfin, vous pouvez configurer une synchronisation planifiée périodique, toujours avec les fonctions ContentResolver.
6. Examiner les implications de plusieurs comptes
Il est possible d'avoir plus d'un compte du même type (deux comptes @ gmail.com configurés sur un appareil ou deux comptes facebook, ou deux comptes Twitter, etc.). Vous devriez considérer les implications applicatives de cela. .. Si vous avez deux comptes, vous ne voudrez probablement pas essayer de les synchroniser tous les deux dans les mêmes tables de base de données. Vous devez peut-être spécifier qu'un seul peut être actif à la fois, vider les tables et resynchroniser si vous changez de compte. (via une page de propriétés qui demande quels comptes sont présents). Peut-être que vous créez une base de données différente pour chaque compte, peut-être des tables différentes, peut-être une colonne clé dans chaque table. Toutes les applications sont spécifiques et dignes de réflexion.
ContentResolver.setIsSyncable(Account account, String authority, int syncable)
pourrait être intéressant ici.setSyncAutomatically()
contrôle si une paire compte / autorité est cochée ounon cochée , alors quesetIsSyncable()
fournit un moyen de décocher et de griser la ligne afin que l'utilisateur ne puisse pas l'activer. Vous pouvez définir un compte Syncable et l'autre non Syncable (dsabled).7. Soyez conscient de ContentResolver.notifyChange ()
Une chose délicate.
ContentResolver.notifyChange()
est une fonction utilisée parContentProvider
s pour informer Android que la base de données locale a été modifiée. Cela remplit deux fonctions, premièrement, cela entraînera la mise à jour des curseurs suivant cet uri de contenu, et à son tour la requery et l'invalidation et le redessiner d'unListView
, etc ... C'est très magique, la base de données change et votreListView
juste mise à jour automatiquement. Impressionnant. De plus, lorsque la base de données change, Android demandera Sync pour vous, même en dehors de votre horaire normal, afin que ces modifications soient supprimées de l'appareil et synchronisées avec le serveur le plus rapidement possible. Aussi génial.Il y a cependant un cas de pointe. Si vous tirez du serveur et poussez une mise à jour dans le
ContentProvider
, il appellera consciencieusementnotifyChange()
et Android dira, "Oh, les changements de base de données, mieux vaut les mettre sur le serveur!" (Doh!) Bien écritContentProviders
aura des tests pour voir si les changements viennent du réseau ou de l'utilisateur, et définira lesyncToNetwork
drapeau booléen sur false si c'est le cas, pour éviter cette double synchronisation inutile. Si vous introduisez des données dans unContentProvider
, il vous incombe de déterminer comment faire fonctionner cela - Sinon, vous finirez par toujours effectuer deux synchronisations quand une seule est nécessaire.8. Sentez-vous heureux!
Une fois que toutes ces métadonnées xml sont en place et que la synchronisation est activée, Android saura comment tout connecter pour vous et la synchronisation devrait commencer à fonctionner. À ce stade, beaucoup de choses agréables se mettront en place et cela ressemblera beaucoup à de la magie. Prendre plaisir!
la source
ContentResolver.SYNC_EXTRAS_MANUAL
jeu à true auJe calmerais
setIsSyncable
après lasetAuthToken
méthode . Mais lasetAuthToken
fonction retournée avant asetIsSyncable
été atteinte. Une fois la commande modifiée, tout fonctionnait bien!la source