Próbuję zaimplementować wzorzec adaptera Content-Provider-Sync, jak omówiono w Google IO - slajd 26. Mój dostawca treści działa, a moja synchronizacja działa, gdy uruchamiam ją z aplikacji Dev Tools Sync Tester, ale gdy wywołuję ContentResolver. requestSync (konto, uprawnienia, pakiet) z mojego dostawcy treści, moja synchronizacja nigdy nie jest wyzwalana.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
Edycja - dodany fragment manifestu Mój manifest xml zawiera:
<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>
--Edytować
Mój syncadapter.xml powiązany z moją usługą synchronizacji zawiera:
<?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"
/>
Nie jestem pewien, jaki inny kod byłby przydatny. Konto przekazane do requestSync ma wartość „myaccounttype”, a AUTORYTET przekazany do wywołania jest zgodny z moim adapterem syc xml.
Czy ContentResolver.requestSync to właściwy sposób żądania synchronizacji? Wygląda na to, że narzędzie do testowania synchronizacji łączy się bezpośrednio z usługą i wywołuje synchronizację, ale wydaje się, że nie spełnia ono celu integracji z architekturą synchronizacji.
Jeśli to jest właściwy sposób żądania synchronizacji, to dlaczego tester synchronizacji miałby działać, ale nie moje wywołanie ContentResolver.requestSync? Czy jest coś, co muszę przekazać w pakiecie?
Testuję w emulatorze na urządzeniach z systemem 2.1 i 2.2.
android:process=":sync"
z usługi synchronizacji niech debugger trafi w punkty dziobowe. Sama usługa synchronizacji działała wcześniej, ponieważ mogłem zobaczyć komunikaty dziennika zonPerformSync
metody w imieniu innego procesu.Odpowiedzi:
Wywołanie
requestSync()
będzie działać tylko na parze {Account, ContentAuthority}, która jest znana w systemie. Twoja aplikacja musi wykonać szereg czynności, aby poinformować Androida, że możesz synchronizować określony rodzaj treści przy użyciu określonego rodzaju konta. Robi to w AndroidManifest.1. Powiadom system Android, że pakiet aplikacji zapewnia synchronizację
Po pierwsze, w AndroidManifest.xml musisz zadeklarować, że masz usługę synchronizacji:
Atrybut name
<service>
tagu to nazwa Twojej klasy, z którą chcesz się połączyć, synchronizować ... Porozmawiam o tym za chwilę.Ustawienie exported true sprawia, że jest on widoczny dla innych komponentów (jest to potrzebne, aby
ContentResolver
można było to wywołać).Filtr intencji pozwala przechwycić intencję żądającą synchronizacji. (Wynika
Intent
to zContentResolver
wywołaniaContentResolver.requestSync()
lub powiązanych metod planowania).<meta-data>
Tag zostaną omówione poniżej.2. Zapewnij Androidowi usługę używaną do znajdowania adaptera SyncAdapter
A więc sama klasa ... Oto przykład:
Twoja klasa musi rozszerzać
Service
lub jedną z jej podklas, musi implementowaćpublic IBinder onBind(Intent)
i musi zwracać,SyncAdapterBinder
gdy jest wywoływana ... Potrzebujesz zmiennej typuAbstractThreadedSyncAdapter
. Jak widać, to prawie wszystko w tej klasie. Jedynym powodem, dla którego istnieje, jest zapewnienie usługi, która oferuje standardowy interfejs dla Androida do wysyłania zapytań Twojej klasie o to, czymSyncAdapter
ona jest.3. Podaj,
class SyncAdapter
aby faktycznie wykonać synchronizację.mySyncAdapter jest miejscem, w którym przechowywana jest sama logika synchronizacji. Jego
onPerformSync()
metoda jest wywoływana, gdy nadejdzie czas na synchronizację. Myślę, że masz już to na miejscu.4. Ustanów powiązanie między typem konta a uprawnieniami do treści
Patrząc ponownie na AndroidManifest, ten dziwny
<meta-data>
tag w naszej usłudze jest kluczowym elementem, który ustanawia powiązanie między ContentAuthority a kontem. Zewnętrznie odwołuje się do innego pliku xml (nazwij go jak chcesz, coś związanego z twoją aplikacją). Spójrzmy na sync_myapp.xml:Ok, więc co to robi? Mówi Androidowi, że zdefiniowany przez nas adapter synchronizacji (klasa, która została wywołana w elemencie name
<service>
tagu zawierającym<meta-data>
tag odwołujący się do tego pliku ...) zsynchronizuje kontakty przy użyciu konta w stylu com.google.Cała zawartość Ciągi autoryzacji muszą być zgodne i zgodne z tym, co synchronizujesz - powinien to być zdefiniowany przez Ciebie ciąg, jeśli tworzysz własną bazę danych, lub jeśli synchronizujesz znane, powinieneś użyć niektórych istniejących ciągów urządzeń typy danych (takie jak kontakty, wydarzenia w kalendarzu lub informacje o Tobie). Powyższe („com.android.contacts”) jest ciągiem ContentAuthority dla danych typu kontaktów (niespodzianka, niespodzianka).
accountType musi również pasować do jednego z tych znanych typów kont, które zostały już wprowadzone, lub musi pasować do tego, który tworzysz (obejmuje to utworzenie podklasy AccountAuthenticator w celu uzyskania autoryzacji na serwerze ... Warto sam artykuł). Ponownie „com.google” to zdefiniowany ciąg znaków identyfikujący dane logowania do konta w stylu ... google.com (znowu nie powinno to być zaskoczeniem).
5. Włącz synchronizację na danej parze Konto / ContentAuthority
Na koniec należy włączyć synchronizację. Możesz to zrobić na stronie Konta i synchronizacja w panelu sterowania, przechodząc do aplikacji i zaznaczając pole wyboru obok aplikacji na odpowiednim koncie. Alternatywnie możesz to zrobić w kodzie konfiguracji w swojej aplikacji:
Aby nastąpiła synchronizacja, Twoja para konto / uprawnienia musi być włączona do synchronizacji (jak powyżej), a ogólna flaga globalnej synchronizacji w systemie musi być ustawiona, a urządzenie musi mieć łączność z siecią.
Jeśli synchronizacja konta / uprawnień lub synchronizacja globalna są wyłączone, wywołanie RequestSync () ma wpływ - ustawia flagę, że zażądano synchronizacji i zostanie wykonana, gdy tylko synchronizacja zostanie włączona.
Ponadto, na mgv , ustawienie
ContentResolver.SYNC_EXTRAS_MANUAL
na true w pakiecie dodatków twojego requestSync poprosi Androida o wymuszenie synchronizacji, nawet jeśli globalna synchronizacja jest wyłączona (szanuj tutaj swojego użytkownika!)Na koniec możesz skonfigurować okresową zaplanowaną synchronizację, ponownie z funkcjami ContentResolver.
6. Rozważ konsekwencje wielu kont
Możliwe jest posiadanie więcej niż jednego konta tego samego typu (dwa konta @ gmail.com założone na jednym urządzeniu lub dwa konta na Facebooku, lub dwa konta na Twitterze, itd.). Należy rozważyć konsekwencje dla aplikacji. .. Jeśli masz dwa konta, prawdopodobnie nie chcesz próbować synchronizować ich obu w tych samych tabelach bazy danych. Może musisz określić, że tylko jeden może być aktywny w danym momencie, a także opróżnić tabele i ponownie zsynchronizować, jeśli zmienisz konto. (poprzez stronę właściwości, która pyta, jakie konta są obecne). Może tworzysz inną bazę danych dla każdego konta, może różne tabele, może kolumnę klucza w każdej tabeli. Wszystkie aplikacje specyficzne i warte przemyślenia.
ContentResolver.setIsSyncable(Account account, String authority, int syncable)
może być tutaj interesujące.setSyncAutomatically()
kontroluje, czy sprawdzana jest para konto / uprawnienia, czyniezaznaczone , alesetIsSyncable()
umożliwia odznaczenie i wyszarzenie linii, aby użytkownik nie mógł jej włączyć. Możesz ustawić jedno konto jako Syncable, a drugie jako Not Syncable (dsabled).7. Pamiętaj o ContentResolver.notifyChange ()
Jedna trudna rzecz.
ContentResolver.notifyChange()
to funkcja używana przezContentProvider
s do powiadamiania systemu Android o zmianie lokalnej bazy danych. Służy to dwóm funkcjom, po pierwsze, spowoduje aktualizację kursorów podążających za tą zawartością uri, a następnie ponowne zażądanie, unieważnienie i ponowne narysowanieListView
, itd. To bardzo magiczne, baza danych zmienia się, aListView
po prostu aktualizuje się automatycznie. Niesamowite. Ponadto, gdy baza danych ulegnie zmianie, system Android zażąda synchronizacji, nawet poza normalnym harmonogramem, aby zmiany te zostały usunięte z urządzenia i zsynchronizowane z serwerem tak szybko, jak to możliwe. Również super.Jest jednak jeden skrajny przypadek. Jeśli ściągniesz z serwera i wepchniesz aktualizację do
ContentProvider
, to sumiennie zadzwoni,notifyChange()
a android powie: „Och, zmiany w bazie danych, lepiej umieść je na serwerze!” (Doh!) Dobrze napisanyContentProviders
będzie miał kilka testów, aby sprawdzić, czy zmiany pochodziły z sieci, czy od użytkownika, i ustawisyncToNetwork
flagę boolean na false, jeśli tak, aby zapobiec marnotrawnej podwójnej synchronizacji. Jeśli dostarczasz dane do aContentProvider
, powinieneś dowiedzieć się, jak to działa - w przeciwnym razie zawsze będziesz wykonywać dwie synchronizacje, gdy tylko jedna będzie potrzebna.8. Ciesz się!
Gdy masz już wszystkie te metadane xml i włączasz synchronizację, Android będzie wiedział, jak połączyć wszystko za Ciebie, a synchronizacja powinna zacząć działać. W tym momencie wiele fajnych rzeczy po prostu zatrzaśnie się na swoim miejscu i będzie to trochę jak magia. Cieszyć się!
źródło
ContentResolver.SYNC_EXTRAS_MANUAL
zestaw true do zestawu dodatków, aKorzystałem z metody
setIsSyncable
AccountManagersetAuthToken
. AlesetAuthToken
funkcja zwrócona wcześniejsetIsSyncable
została osiągnięta. Po zmianie zamówienia wszystko działało dobrze!źródło