ContentResolver.requestSync neden bir senkronizasyon tetiklemiyor?


112

Google IO'da tartışıldığı gibi Content-Provider-Sync Adapter modelini uygulamaya çalışıyorum - slayt 26. İçerik sağlayıcım çalışıyor ve senkronizasyonum onu ​​Dev Tools Sync Tester uygulamasından tetiklediğimde ancak ContentResolver'ı çağırdığımda çalışıyor. ContentProvider'ımdan requestSync (hesap, yetki, paket), senkronizasyonum asla tetiklenmiyor.

ContentResolver.requestSync(
        account, 
        AUTHORITY, 
        new Bundle());

Düzenle - manifest snippet'i eklendi Manifest xml'im şunları içerir:

<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>

--Düzenle

Eşitleme hizmetimle ilişkili syncadapter.xml dosyam şunları içerir:

<?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"
/>

Başka hangi kodun yararlı olacağından emin değilim. RequestSync'e aktarılan hesap "myaccounttype" türünde ve çağrıya aktarılan AUTHORITY, benim syc Adapter xml ile eşleşiyor.

ContentResolver.requestSync, bir senkronizasyon talep etmenin doğru yolu mudur? Senkronizasyon test aracı doğrudan hizmete bağlanıyor ve çağrılar senkronizasyonu başlatıyor gibi görünüyor, ancak bu, senkronizasyon mimarisiyle bütünleşme amacını ortadan kaldırıyor gibi görünüyor.

Bir senkronizasyon talep etmenin doğru yolu buysa, o zaman neden ContentResolver.requestSync çağrım olmasa da senkronizasyon test cihazı çalışır? Pakette geçmem gereken bir şey var mı?

Emülatörde 2.1 ve 2.2 çalıştıran cihazlarda test ediyorum.


3
Benim sorunum, senkronizasyon adaptöründeki kırılma noktasına ulaşılamamasıydı ... Sonra bir hizmette hata ayıklamaya çalıştığımı fark ettim ... Umarım bu benim gibi başkalarına yardımcı olur.
dangalg

2
Senkronizasyon adaptörü hizmetindeki kesme noktaları tetiklenemeyecek. Bunun nedeni, eşitleme bağdaştırıcısı hizmetinin ayrı bir işlemde çalışmasıdır. @ Danglang'ın ima ettiği şey buydu. Ayrıca şu soruya bakın: stackoverflow.com/questions/8559458/…
Konstantin Schubert

1
Benim durumumda android:process=":sync", senkronizasyon servisinden çıkarılması , hata ayıklayıcının gaga noktalarına çarpmasına izin verin. Senkronizasyon hizmetinin kendisi bundan önce çalışıyordu, çünkü onPerformSyncbaşka bir işlem adına yöntemden günlük mesajlarını görebiliyordum .
Sergey

Diğer bir neden de WiFi'nin kapalı olmasıdır, bu nedenle alay edilen verilerle senkronize etmeye çalışıyorsanız, bağlantınızı kontrol edin.
Allan Veloso

Yanıtlar:


280

Çağrı requestSync(), yalnızca sistem tarafından bilinen bir {Account, ContentAuthority} çifti üzerinde çalışacaktır. Uygulamanızın, Android'e belirli bir hesap türü kullanarak belirli bir tür içeriği senkronize edebileceğinizi söylemek için birkaç adımdan geçmesi gerekir. Bunu AndroidManifest'te yapar.

1. Android'e uygulama paketinizin senkronizasyon sağladığını bildirin

Öncelikle, AndroidManifest.xml'de bir Eşitleme Hizmetine sahip olduğunuzu beyan etmeniz gerekir:

<service android:name=".sync.mySyncService" android:exported="true">
   <intent-filter>
      <action android:name="android.content.SyncAdapter" /> 
    </intent-filter>
    <meta-data 
        android:name="android.content.SyncAdapter" 
        android:resource="@xml/sync_myapp" /> 
</service>

<service>Etiketin name özniteliği, senkronizasyonu bağlamak için sınıfınızın adıdır ... Bununla biraz sonra konuşacağım.

Dışa aktarılan true ayarı, diğer bileşenlere görünür hale getirir (gerekli olduğu ContentResolveriçin çağrılabilir).

Amaç filtresi, senkronizasyon isteyen bir amacı yakalamasını sağlar. (Bu Intent, ContentResolveraradığınızda ContentResolver.requestSync()veya ilgili zamanlama yöntemlerinden gelir.)

<meta-data>Etiket aşağıda ele alınacaktır.

2. Android'e SyncAdapter bulmak için kullanılan bir hizmet sağlayın

Yani sınıfın kendisi ... İşte bir örnek:

public class mySyncService extends Service {

    private static mySyncAdapter mSyncAdapter = null;

    public SyncService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (mSyncAdapter == null) {
            mSyncAdapter = new mySyncAdapter(getApplicationContext(), true);
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return mSyncAdapter.getSyncAdapterBinder();
    }
}

Sınıfınız genişletilmeli Serviceveya alt sınıflarından biri uygulanmalı public IBinder onBind(Intent)ve SyncAdapterBinderçağrıldığında bir döndürmelidir ... Bir tür değişkenine ihtiyacınız var AbstractThreadedSyncAdapter. Gördüğünüz gibi, bu sınıftaki hemen hemen her şey. Var olmasının tek nedeni, Android'in sınıfınızı kendinizin ne olduğu konusunda sorgulaması için standart bir arayüz sunan bir Hizmet sağlamaktır SyncAdapter.

3. class SyncAdapterEşitlemeyi gerçekten gerçekleştirmek için a sağlayın .

mySyncAdapter, gerçek eşitleme mantığının kendisinin depolandığı yerdir. Onun onPerformSync()zamanı senkronizasyonu geldiğinde yöntem çağrılır. Sanırım bunu zaten yerine getirdin.

4. Bir Hesap türü ile bir İçerik Yetkilisi arasında bir bağlantı kurun

AndroidManifest'e tekrar dönüp baktığımızda <meta-data>, hizmetimizdeki bu garip etiket, bir ContentAuthority ile bir hesap arasındaki bağlantıyı kuran anahtar parçadır. Harici olarak başka bir xml dosyasına referansta bulunur (istediğinizi adlandırın, uygulamanızla ilgili bir şey.) Sync_myapp.xml'e bakalım:

<?xml version="1.0" encoding="utf-8" ?> 
<sync-adapter 
    xmlns:android="http://schemas.android.com/apk/res/android"   
    android:contentAuthority="com.android.contacts"
    android:accountType="com.google" 
    android:userVisible="true" /> 

Tamam, peki bu ne yapıyor? Android'e, tanımladığımız senkronizasyon adaptörünün ( bu dosyaya referans <service>veren <meta-data>etiketi içeren etiketin ad öğesinde çağrılan sınıf ...) kişileri com.google tarzı bir hesap kullanarak senkronize edeceğini söyler.

Tüm contentAuthority dizelerinizin tümü eşleşmeli ve senkronize ettiğiniz şeyle eşleşmelidir - Bu, kendi veritabanınızı oluşturuyorsanız tanımladığınız bir dize olmalıdır veya senkronize ediyorsanız bazı mevcut cihaz dizelerini kullanmalısınız. veri türleri (kişiler veya takvim etkinlikleri gibi veya sizde ne var.) Yukarıdaki ("com.android.contacts"), kişi türü verileri (sürpriz, sürpriz) için ContentAuthority dizesidir.

accountType ayrıca önceden girilmiş olan bilinen hesap türlerinden biriyle eşleşmeli veya oluşturduğunuz hesap türleriyle eşleşmelidir (Bu, sunucunuzda kimlik doğrulaması almak için bir AccountAuthenticator alt sınıfı oluşturmayı içerir ... Bir makaleye değer.) Yine "com.google", google.com tarzı hesap kimlik bilgilerini tanımlayan tanımlı dizedir (yine, bu bir sürpriz olmamalıdır.)

5. Belirli bir Hesap / ContentAuthority çiftinde Senkronizasyonu etkinleştirin

Son olarak, senkronizasyonun etkinleştirilmesi gerekir. Bunu, kontrol panelindeki Hesaplar ve Senkronizasyon sayfasında uygulamanıza gidip eşleşen hesapta uygulamanızın yanındaki onay kutusunu ayarlayarak yapabilirsiniz. Alternatif olarak, bunu uygulamanızdaki bazı kurulum kodlarında yapabilirsiniz:

ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

Senkronizasyonun gerçekleşmesi için, hesap / yetki çiftinizin senkronizasyon için etkinleştirilmesi (yukarıdaki gibi) ve sistemdeki genel global senkronizasyon bayrağının ayarlanması ve cihazın ağ bağlantısının olması gerekir.

Hesabınız / yetki eşitlemeniz veya genel eşitleme devre dışı bırakılırsa, RequestSync () 'i çağırmanın bir etkisi olur - Eşitlemenin istendiği bir bayrak belirler ve eşitleme etkinleştirilir etkinleştirilmez gerçekleştirilir.

Ayrıca, mgv başına, isteğinizinContentResolver.SYNC_EXTRAS_MANUAL ekstra paketinde doğru olarak ayarlamak , Android'den global senkronizasyon kapalı olsa bile bir senkronizasyonu zorlamasını ister (burada kullanıcınıza karşı saygılı olun!)

Son olarak, yine ContentResolver işlevleriyle periyodik bir zamanlanmış senkronizasyon ayarlayabilirsiniz.

6. Birden çok hesabın sonuçlarını düşünün

Aynı türden birden fazla hesaba sahip olmak mümkündür (bir cihazda veya iki facebook hesabında kurulu iki @ gmail.com hesabı veya iki twitter hesabı, vb.) Bunu yapmanın uygulama sonuçlarını göz önünde bulundurmalısınız. .. İki hesabınız varsa, muhtemelen her ikisini de aynı veritabanı tablolarına eşitlemeyi denemek istemezsiniz. Belki bir seferde yalnızca birinin etkin olabileceğini belirtmeniz ve hesap değiştirirseniz tabloları temizleyip yeniden senkronize etmeniz gerekebilir. (hangi hesapların mevcut olduğunu sorgulayan bir mülk sayfası aracılığıyla). Belki her hesap için farklı bir veritabanı, belki farklı tablolar, belki her tabloda bir anahtar sütun oluşturursunuz. Tüm uygulamalara özel ve biraz düşünmeye değer. ContentResolver.setIsSyncable(Account account, String authority, int syncable)burada ilgi çekici olabilir. setSyncAutomatically()bir hesap / yetki çiftinin kontrol edilip edilmeyeceğini kontrol eder veyaişaretlenmemiş , oysa setIsSyncable()hattın işaretini kaldırıp grileştirmenin bir yolunu sağlar , böylece kullanıcı onu açamaz. Bir hesabı Senkronize Edilebilir, diğerini Senkronize Edilemez (dsabled) olarak ayarlayabilirsiniz.

7. ContentResolver.notifyChange () konusunda bilgi sahibi olun

Zor bir şey. s ContentResolver.notifyChange()tarafından ContentProviderAndroid'e yerel veritabanının değiştirildiğini bildirmek için kullanılan bir işlevdir . Bu, iki işleve hizmet eder, birincisi, içerik uri'nin ardından gelen imleçlerin güncellenmesine ve daha sonra a ListView, vb.'nin yeniden sorgulanmasına ve geçersiz kılınmasına ve yeniden çizilmesine neden olur ... Bu çok sihirli, veritabanı değişir ve ListViewyalnızca otomatik olarak güncellemeleriniz. Muhteşem. Ayrıca, veritabanı değiştiğinde, Android, normal programınızın dışında bile sizin için Senkronizasyon talep eder, böylece bu değişiklikler cihazdan çıkarılır ve mümkün olan en hızlı şekilde sunucuyla senkronize edilir. Ayrıca harika.

Yine de bir uç durum var. Sunucudan çeker ve bir güncellemeyi içine gönderirseniz, görev ContentProviderbilinciyle arayacak notifyChange()ve android "Oh, veritabanı değişiklikleri, bunları sunucuya koysanız iyi olur!" (Doh!) ContentProvidersDeğişikliklerin ağdan mı yoksa kullanıcıdan mı geldiğini görmek için iyi yazılmış bazı testler olacak ve syncToNetworkeğer öyleyse bu gereksiz çift senkronizasyonu önlemek için boole bayrağını yanlış ayarlayacaktır . Bir veriyi ContentProvidera'ya besliyorsanız , bunun nasıl çalıştırılacağını anlamanız gerekir - Aksi takdirde, yalnızca birine ihtiyaç duyulduğunda her zaman iki senkronizasyon gerçekleştirirsiniz.

8. Mutlu hissedin!

Tüm bu xml meta verilerini yerleştirip senkronizasyonu etkinleştirdikten sonra, Android her şeyi sizin için nasıl bağlayacağını bilecek ve senkronizasyon çalışmaya başlayacaktır. Bu noktada, hoş olan pek çok şey yerine oturacak ve sihir gibi hissedecek. Zevk almak!


11
ContentResolver.setSyncAutomatically (hesap, AUTHORITY, true);
jcwenger

1
Sorun Değil, yardımcı olabildiğime sevindim. Yine bir stil açısından bakıldığında, eğer "AUTHORITY" ve "myaccounttype" kullandığınız gerçek dizeler ise (Ve sadece siteye kopyalamaya yönelik örnekler değil), kesinlikle adlandırma kurallarınızı temizlemeniz gerekir. Bu dizelerin tüm cihazda benzersiz olması gerekir ve başka bir programcı, yetki için tembel bir şekilde eşleşen bir dizeye sahip bir paket oluşturursa ve bir çelişki yaşarsanız gerçek bir sorunla karşılaşırsınız. Şerefe!
jcwenger

22
Global senkronizasyon ayarları kapalı olsa bile bir senkronizasyon talep edebilirsiniz. ContentResolver.SYNC_EXTRAS_MANUALEkstra
Pakete

2
@kaciula: Hiçbirini bilmiyorum, ancak cihaz senkronize edilmesi gerektiğini hatırlayacak ve global senkronizasyon açılır açılmaz bir tane başlatacak. Bu konuda kullanıcıyı gerçekten gölgede bırakmaya çalışmamalısınız - Özellikle "Global senkronizasyon kapalı" kritik durumlarda pilden tasarruf etmenin anahtar yollarından biri olduğu için. Verilerin senkronize edilmemesi konusunda gerçekten endişeleniyorsanız, kullanıcıya bir süredir oturuyorsa verilerin NEDEN hareket etmediğini söyleyen bir açılır pencere düşünün. Bu şekilde, yanlışlıkla cihazlarını yanlış yapılandıran kullanıcıları eğitebilir ve unutmaları durumunda uzman kullanıcılara hatırlatabilirsiniz.
jcwenger

2
AddPeriodicSync () 'i kullanmak istiyorsanız, YALNIZCA setSyncAutomatically () de çalışıyorsanız işe yarayacağını eklemeye değer olabilir - Bunu umutsuzluğumdan ekledim, BİR ŞEY çalışmaya başladım. Bunun orijinal sorunun bir parçası olmadığını biliyorum, ama bu çok eksiksiz bir cevap!
android.weasel

0

setIsSyncableAccountManager setAuthTokenyönteminden sonra arıyordum . Ancak daha setAuthTokenönce döndürülen işleve setIsSyncableulaşıldı. Sipariş değişikliklerinden sonra her şey yolunda gitti!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.