Ich versuche, das Content-Provider-Sync-Adapter-Muster zu implementieren, wie in Google IO - Folie 26 beschrieben. Mein Content-Provider funktioniert und meine Synchronisierung funktioniert, wenn ich es über die Dev Tools Sync Tester-Anwendung auslöse, jedoch wenn ich ContentResolver aufrufe. requestSync (Konto, Berechtigung, Bundle) von meinem ContentProvider, meine Synchronisierung wird niemals ausgelöst.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
Bearbeiten - Manifest-Snippet hinzugefügt Meine Manifest-XML enthält:
<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>
--Bearbeiten
Meine mit meinem Synchronisierungsdienst verknüpfte Datei syncadapter.xml enthält:
<?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"
/>
Ich bin mir nicht sicher, welcher andere Code nützlich wäre. Das an requestSync übergebene Konto ist vom Typ "myaccounttype" und die an den Aufruf übergebene AUTHORITY stimmt mit meiner Syc-Adapter-XML überein.
Ist ContentResolver.requestSync der richtige Weg, um eine Synchronisierung anzufordern? Es sieht so aus, als ob das Sync-Tester-Tool direkt an den Dienst gebunden ist und Aufrufe die Synchronisierung starten, aber das scheint den Zweck der Integration in die Sync-Architektur zu vereiteln.
Wenn dies der richtige Weg ist, um eine Synchronisierung anzufordern, warum sollte dann der Synchronisierungstester funktionieren, aber nicht mein Aufruf von ContentResolver.requestSync? Muss ich etwas im Bundle weitergeben?
Ich teste im Emulator auf Geräten mit 2.1 und 2.2.
android:process=":sync"
aus dem Synchronisierungsdienst den Debugger die Schnabelpunkte treffen. Der Synchronisierungsdienst selbst funktionierte zuvor, da ich Protokollnachrichten von deronPerformSync
Methode im Auftrag eines anderen Prozesses sehen konnte.Antworten:
Das Aufrufen
requestSync()
funktioniert nur für ein dem Konto bekanntes Paar {Account, ContentAuthority}. Ihre App muss eine Reihe von Schritten durchlaufen, um Android mitzuteilen, dass Sie in der Lage sind, eine bestimmte Art von Inhalten mit einer bestimmten Art von Konto zu synchronisieren. Dies geschieht im AndroidManifest.1. Benachrichtigen Sie Android, dass Ihr Anwendungspaket die Synchronisierung bietet
Zunächst müssen Sie in AndroidManifest.xml erklären, dass Sie über einen Synchronisierungsdienst verfügen:
Das Namensattribut des
<service>
Tags ist der Name Ihrer Klasse, um die Synchronisierung herzustellen ... Ich werde gleich darauf eingehen.Wenn Sie exported true festlegen, wird es für andere Komponenten sichtbar (erforderlich)
ContentResolver
es aufgerufen werden kann).Mit dem Absichtsfilter kann eine Absicht erfasst werden, die eine Synchronisierung anfordert. (Dies
Intent
kommt von,ContentResolver
wenn SieContentResolver.requestSync()
oder verwandte Planungsmethoden aufrufen .)Das
<meta-data>
Tag wird unten diskutiert.2. Stellen Sie Android einen Dienst zur Verfügung, mit dem Sie Ihren SyncAdapter finden
Also die Klasse selbst ... Hier ist ein Beispiel:
Ihre Klasse muss eine
Service
oder eine ihrer Unterklassen erweitern, implementierenpublic IBinder onBind(Intent)
und a zurückgeben,SyncAdapterBinder
wenn dies aufgerufen wird ... Sie benötigen eine Variable vom TypAbstractThreadedSyncAdapter
. Wie Sie sehen, ist das so ziemlich alles in dieser Klasse. Der einzige Grund dafür ist die Bereitstellung eines Dienstes, der eine Standardschnittstelle für Android bietet, über die Sie Ihre Klasse nach Ihrer eigenenSyncAdapter
fragen können.3. Geben Sie a
class SyncAdapter
an, um die Synchronisierung tatsächlich durchzuführen.In mySyncAdapter wird die eigentliche Synchronisierungslogik selbst gespeichert. Es ist
onPerformSync()
Methode wird aufgerufen, wenn die Synchronisierung abgeschlossen ist. Ich denke, Sie haben dies bereits eingerichtet.4. Stellen Sie eine Bindung zwischen einem Kontotyp und einer Inhaltsbehörde her
Wenn wir noch einmal auf AndroidManifest zurückblicken, ist dieses seltsame
<meta-data>
Tag in unserem Service das Schlüsselelement, das die Bindung zwischen einer ContentAuthority und einem Konto herstellt. Es verweist extern auf eine andere XML-Datei (nennen Sie es wie Sie möchten, etwas, das für Ihre App relevant ist.) Schauen wir uns sync_myapp.xml an:Okay, was macht das? Es teilt Android mit, dass der von uns definierte Synchronisierungsadapter (die Klasse, die im name-Element des
<service>
Tags aufgerufen wurde, das das Tag enthält, das<meta-data>
auf diese Datei verweist ...) Kontakte über ein Konto im com.google-Stil synchronisiert.Alle Ihre contentAuthority-Zeichenfolgen müssen mit dem übereinstimmen, was Sie synchronisieren. Dies sollte eine Zeichenfolge sein, die Sie definieren, wenn Sie eine eigene Datenbank erstellen, oder Sie sollten einige vorhandene Gerätezeichenfolgen verwenden, wenn Sie die Synchronisierung durchführen Datentypen (wie Kontakte oder Kalenderereignisse oder was haben Sie). Das oben Gesagte ("com.android.contacts") ist zufällig die ContentAuthority-Zeichenfolge für Kontakttypdaten (Überraschung, Überraschung.)
accountType muss auch mit einem der bekannten Kontotypen übereinstimmen, die bereits eingegeben wurden, oder mit einem, den Sie erstellen (Dies beinhaltet das Erstellen einer Unterklasse von AccountAuthenticator, um die Authentifizierung auf Ihrem Server zu erhalten ... Ein Artikel ist es wert.) Wiederum ist "com.google" die definierte Zeichenfolge, die die Anmeldeinformationen eines Kontos im Google.com-Stil identifiziert (auch dies sollte keine Überraschung sein.)
5. Aktivieren Sie die Synchronisierung für ein bestimmtes Konto / ContentAuthority-Paar
Schließlich muss die Synchronisierung aktiviert werden. Sie können dies auf der Seite "Konten und Synchronisierung" in der Systemsteuerung tun, indem Sie zu Ihrer App gehen und das Kontrollkästchen neben Ihrer App im entsprechenden Konto aktivieren. Alternativ können Sie dies in einem Setup-Code in Ihrer App tun:
Damit eine Synchronisierung stattfinden kann, muss Ihr Konto- / Berechtigungspaar für die Synchronisierung aktiviert sein (wie oben), und das allgemeine globale Synchronisierungsflag auf dem System muss gesetzt sein, und das Gerät muss über eine Netzwerkverbindung verfügen.
Wenn die Synchronisierung Ihres Kontos / Ihrer Behörde oder die globale Synchronisierung deaktiviert ist, hat der Aufruf von RequestSync () Auswirkungen. Er setzt ein Flag, dass die Synchronisierung angefordert wurde, und wird ausgeführt, sobald die Synchronisierung aktiviert ist.
Auch pro mgv Einstellung
ContentResolver.SYNC_EXTRAS_MANUAL
im Extras-Bundle Ihrer auf true wird Android aufgefordert, eine Synchronisierung zu erzwingen, auch wenn die globale Synchronisierung ist (respektieren Sie Ihren Benutzer hier!).Schließlich können Sie eine regelmäßige geplante Synchronisierung erneut mit ContentResolver-Funktionen einrichten.
6. Berücksichtigen Sie die Auswirkungen mehrerer Konten
Es ist möglich, mehr als ein Konto desselben Typs zu haben (zwei @ gmail.com-Konten auf einem Gerät oder zwei Facebook-Konten oder zwei Twitter-Konten usw.). Sie sollten die Auswirkungen der Anwendung berücksichtigen. .. Wenn Sie zwei Konten haben, möchten Sie wahrscheinlich nicht versuchen, beide mit denselben Datenbanktabellen zu synchronisieren. Möglicherweise müssen Sie angeben, dass jeweils nur eine aktiv sein kann, und die Tabellen leeren und erneut synchronisieren, wenn Sie das Konto wechseln. (über eine Eigenschaftsseite, die abfragt, welche Konten vorhanden sind). Vielleicht erstellen Sie für jedes Konto eine andere Datenbank, vielleicht verschiedene Tabellen, vielleicht eine Schlüsselspalte in jeder Tabelle. Alle anwendungsspezifisch und bedenkenswert.
ContentResolver.setIsSyncable(Account account, String authority, int syncable)
könnte hier von Interesse sein.setSyncAutomatically()
steuert, ob ein Konto / Berechtigungspaar geprüft wird oderdeaktiviert , während essetIsSyncable()
eine Möglichkeit bietet, die Linie zu deaktivieren und auszublenden, damit der Benutzer sie nicht aktivieren kann. Sie können festlegen, dass ein Konto synchronisierbar und das andere nicht synchronisierbar ist (dsabled).7. Beachten Sie ContentResolver.notifyChange ()
Eine knifflige Sache.
ContentResolver.notifyChange()
ist eine Funktion, mit derContentProvider
s Android benachrichtigt, dass die lokale Datenbank geändert wurde. Dies hat zwei Funktionen: Erstens führt dies dazu, dass Cursor, die diesem Inhalts-Uri folgen, aktualisiert werden und im Gegenzug einListView
usw. anfordern und ungültig machen und neu zeichnen. Es ist sehr magisch, die Datenbank ändert sich und IhreListView
nur automatisch aktualisiert. Genial. Wenn sich die Datenbank ändert, fordert Android auch außerhalb Ihres normalen Zeitplans die Synchronisierung für Sie an, damit diese Änderungen vom Gerät entfernt und so schnell wie möglich mit dem Server synchronisiert werden. Auch super.Es gibt jedoch einen Randfall. Wenn Sie vom Server ziehen und ein Update in den Server schieben
ContentProvider
, wird es pflichtbewusst aufgerufennotifyChange()
und Android sagt: "Oh, Datenbankänderungen, stellen Sie sie besser auf den Server!" (Doh!) Gut geschriebenContentProviders
hat einige Tests, um festzustellen, ob die Änderungen vom Netzwerk oder vom Benutzer stammen, und setztsyncToNetwork
in diesem Fall das boolesche Flag auf false, um diese verschwenderische Doppelsynchronisierung zu verhindern. Wenn Sie Daten in aContentProvider
einspeisen, müssen Sie herausfinden, wie dies funktioniert. Andernfalls führen Sie immer zwei Synchronisierungen durch, wenn nur eine benötigt wird.8. Fühle dich glücklich!
Sobald Sie alle diese XML-Metadaten eingerichtet und die Synchronisierung aktiviert haben, weiß Android, wie Sie alles für Sie verbinden, und die Synchronisierung sollte beginnen. An diesem Punkt rasten viele Dinge, die schön sind, einfach ein und es wird sich sehr nach Magie anfühlen. Genießen!
quelle
ContentResolver.SYNC_EXTRAS_MANUAL
Ich habe
setIsSyncable
nach der AccountManager-setAuthToken
Methode kalibriert . AbersetAuthToken
zurückgegebene Funktion, bevorsetIsSyncable
erreicht wurde. Nach Bestelländerungen hat alles gut funktioniert!quelle