Mobil Programlama

Android

Sync Adapter Oluşturmak

Lisans: Creative Commons 11.12.2020 tarihinde güncellendi
Bakabileceğiniz Etiketler: Eğitmen: Geleceği Yazanlar Ekibi

Uygulamanızdaki Sync Adapter bileşeni, cihazınız ve sunucu arasında veri aktarımı yapan görevler için gerekli kodu kapsar. Sync adapter çatısı kodu, uygulamanızdaki zamanlama ve tetikleyicilere göre sync adapter bileşeninizin içinde çalıştırır. Uygulamanıza sync adapter bileşeni eklemek için aşağıdaki bileşenleri eklemeniz gerekir:

Sync Adapter sınıfı: Veri aktarım kodunu sync adapter çatısıyla uyumlu bir interface içine saran sınıf.

Bound Service: Sync adapter çatısının, kodunuzu sync adapter sınıfında çalıştırmasını sağlayan bileşendir.

Sync Adapter XML metadata dosyası: Sync adapter'iniz hakkında bilgi saklayan dosyadır. Çatı veri transferinizin zamanlamasını yapmak ve nasıl yükleme yapılacağını öğrenmek için bu dosyayı okur.

App manifest içindeki ifadeler: Bound Service'i tanımlayan bir XML'dir ve sync adapter'in belirlenmiş metadatasını işaret eder.

Bu ders bu bileşenleri nasıl tanımlayacağınızı öğretir.

 

Sync Adapter sınıfı yaratmak

Eğitim içeriğinin bu kısmında veri aktarım kodunu kapsayan bir sync adapter sınıfını nasıl oluşturacağınızı öğreneceksiniz. Bu sınıf oluşturmanın içine, temel sync adapter sınıfından türetmek, bu sınıfın yapılandırıcılarını tanımlamak ve veri aktarımı görevlerini tanımladığınız bir metod oluşturmak dâhildir.

Temel AbstractThreadedSyncAdapter sınıfından türemek: Sync adapter bileşeni oluşturmaya AbstractThreadedSyncAdapter sınıfından türemekle ve onun yapılandırıcılarını yazmakla başlamalısınız. Sync adapter bileşeniniz sıfırdan her oluşturulduğunda, yapılandırıcılar kurulum görevlerini çalıştırmak için kullanın. Tıpkı bir activity kurmak için Activity.onCreate()'i kullandığınız gibi. Örneğin, uygulamanız veri saklamak için bir içerik sağlayıcı kullanıyorsa ContentResolver instance'ini almak için yapılandırıcıları kullanın. Android 3.0'de parallelSyncs argümanını desteklemek için ikinci bir yapılandırıcı tipi eklendiğinden, uyumluluğu sağlamak için sizin de iki tip yapılandırıcı oluşturmanız gerekir.

Not: Sync adapter çatısı, singleton instance olan sync adapter bileşenleriyle çalışmak için tasarlanmıştır. Sync adapter bileşenini kanıtlamak detaylı olarak Sync Adapter'i bir Çatıya Bağlamak bölümünde anlatılmıştır.

Aşağıdaki örnek, AbstractThreadedSyncAdapterand yapılandırıcılarının nasıl yazılacağını göstermektedir:



/**
 * Android sync adapter çatısını kullanarak,
 * sunucu ve uygulama arasındaki veri transferini kontrol etmek.
 */
public class SyncAdapter extends AbstractThreadedSyncAdapter {
    ...
    // Genel değişkenler
    // İçerik çözümleyici instance'i için değişken tanımlamak
    ContentResolver mContentResolver;
    /**
     * Sync adapter'i kurmak
     */
    public SyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
        /*
         * Uygulamanız içerik çözümleyici kullanıyorsa,
         * gelen içerikten instance almak.
         */
        mContentResolver = context.getContentResolver();
    }
    ...
    /**
     * Sync adapter'i kurmak. Bu tip yapılandırıcı
     * Android 3.0 ve sonraki sürümler için uyumluluk gösterir.
     */
    public SyncAdapter(
            Context context,
            boolean autoInitialize,
            boolean allowParallelSyncs) {
        super(context, autoInitialize, allowParallelSyncs);
        
        /* 
         * Uygulamanız içerik çözümleyici kullanıyorsa,
         * gelen içerikten instance almak. 
         */
        mContentResolver = context.getContentResolver();
        ...
    }

 

Veri transfer kodunu onPerformSync()'e eklemek

Sync adapter bileşeni kendiliğinden veri aktarımı yapmaz. Onun yerine veri transfer kodunuzu kapsar, dolayısıyla sync adapter çatısı veri transferinizi uygulamanızdan etkileşim almadan arka planda gerçekleştirebilir. Çatınız uygulamanızın verisini eşlemeye hazır olduğunda yazdığınız onPerformSync() metoduna başvurur.

Uygulamanızın ana kodundan sync adapter bileşenine veri transferini rahatlatmak için, sync adapter çatısı onPerformSync() metodunu aşağıdaki argümanlarla çağırır:

Hesap (Account): Sync adapter'i tetikleyen bir event ile bağlantılı bir hesap nesnesidir. Eğer sunucunuz hesapları kullanmıyorsa, bu nesnedeki bilgileri kullanmanıza gerek yoktur.

Ekler (Extras): Sync adapter tarafından tetiklenmiş eventten gelen bayrakları taşıyan Bundle'dır.

Yetkili (Authority): Sisteminizdeki içerik sağlayıcının yetkilisidir. Uygulamanızın bu sağlayıcıya erişimi olmalıdır. Genelde, yetkili uygulamanızdaki içerik sağlayıcıya eşdeğerdir.

İçerik Sağlayıcı İstemci (Content provider client): Yetkili argümanı tarafından içerik sağlayıcıya yöneltilmiş bir ContentProviderClient'dır. Hafif, herkese açık içerik sağlayıcı interface'idir. ContentResolver ile aynı temel fonksiyonlara sahiptir. Uygulamanız için veriyi içerik sağlayıcı kullanarak saklıyorsanız, sağlayıcıya bu nesne ile bağlanabilirsiniz. Kullanmıyorsanız görmezden gelebilirsiniz.

Eşzamanlama Sonucu (Sync result): Sync adapter çatısına bilgi göndermek için kullandığınız SyncResult nesnesidir.

Aşağıdaki kod parçası onPerformSync()'in genel yapısını gösterir:


/*
     * Sync adapter'de kullanılacak kodu tanımlamak.
     * Tüm sync adapter arkaplan iş parçacığında çalışır, dolayısıyla
     * kendi arkaplan işlerinizi ayarlamanız gerekmez.
     */
    @Override
    public void onPerformSync(
            Account account,
            Bundle extras,
            String authority,
            ContentProviderClient provider,
            SyncResult syncResult) {
    /*
     * Veri aktarım kodu buraya gelecek.
     */
    ...
    }

onPerformSync()'in gerçek yazımı, uygulamanızın eşzamanlama gerekliliklerine ve sunucu bağlantı protokollerine özel olduğu için, kodunuzun gerçekleştirmesi gereken birkaç genel görev vardır:

Sunucuya bağlanmak: Veri aktarımınız başladığında bağlantının uygun olduğunu varsaysanız bile sync adapter çatısı sunucuya otomatik olarak bağlanmaz.

Veri indirmek ve yüklemek: Bir sync adapter veri aktarma görevlerini otomatize etmez. Sunucudan veri indirmek ve bir içerik sağlayıcıda tutmak istiyorsanız, veriyi isteyen, indiren ve sağlayıcıya koyan bir kod yazmanız gerekir. Aynı şekilde eğer sunucuya veri yüklemek istiyorsanız, veriyi dosyadan, veritabanından ya da sağlayıcıdan okuyup gerekli yükleme isteği yapan bir kod yazmanız gerekir.

Veri çakışmalarını yakalayıp mevcut veriye karar vermek: Bir sync adapter sunucudaki ve cihazdaki verilerin arasındaki çakışmayı otomatik olarak yakalamaz. Aynı zamanda cihazdaki verinin sunucudakinden yeni ya da eski olduğunu da otomatik olarak fark etmez. Sizin bu durumları çözecek bir algoritma yazmanız gerekir.

Temizlik: Her veri transferinin sonunda bağlantıları kapatıp, temp dosyalarını ve önbelleği temizlemeniz gerekir.

Not: Sync adapter çatısı onPerformSync()'i bir arkaplan iş parçacığı üzerinde çalıştırır. Dolayısıyla kendiniz arkaplan işlemi kurmak zorunda kalmazsınız.

Eşzamanlama bağlantılı görevlerinize ek olarak düzenli bağlantıyla alakalı görevlerinizi düzenlemeniz ve onPerformSync()'e eklemeniz gerekir. Bütün bağlantı görevlerinizi bu metod içinde düzenleyerek bağlantı kurmak ve bitirmek için gerekli interface'lerin harcadığı batarya ömrünü kazanırsınız. Ağ erişimini daha verimli yapmak için gerekenleri, veri aktarımı kodunuza ekleyebileceğiniz bazı ağ erişim görevlerini tanımlayan Pili Harcamadan Veri Transfer Etmek başlığında görebilirsiniz.

 

Sync Adapter'i bir çatıya bağlamak

Artık veri aktarım kodunuz bir sync adapter bileşeni tarafından kapsanmış durumda ama kodunuza erişim sağlayan bir çatı da oluşturmak zorundasınız. Bunu yapmak için sync adapter bileşeninden çatısına özel bir Android binder nesnesi yollayan bound Service oluşturmalısınız. Bu binder nesnesiyle, çatı onPerformSync() metodunu tanıyabilir ve içine veri yollayabilir.

Sync adapter bileşenini servis içindeki singleton onCreate() metodu olarak kanıtlamanız gerekir. Bu sayede, oluşturmayı servis başlayıncaya kadar erteleyebilirsiniz. Bu da çatı, veri aktarımınızı ilk kez denendiği zaman gerçekleşir. Sync adapter çatısı birden fazla çalıştırmayı sync adapterinize tetikletmeye veya zamanlatmaya çalışırsa diye bu kanıtlamayı iş parçacığını koruyacak şekilde yapmalısınız.

Örneğin, aşağıdaki kod parçası bound Service'i yaratan sınıfı nasıl oluşturacağınızı gösterir, sync adapter bileşeninizi kanıtlar ve Android binder nesnesini alır:

package com.example.android.syncadapter;
/**
 * Sync adapter sınıfı için IBinder dönen bir Service tanımlar.
 * Bu Service sync adapter çatısının 
 * onPerformSync() metodunu çağırmasını sağlar.
 */
public class SyncService extends Service {
    // Sync adapter instance'i için hafıza açar.
    private static SyncAdapter sSyncAdapter = null;
    // İş parçacağı güvencesi için nesne.
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Sync adapter nesnesini tanımlayın.
     */
    @Override
    public void onCreate() {
        /*
         * Sync adapter'i singleton olarak oluşturun.
         * Sync adapter'i eşzamanlamanlanabilir yapın.
         * Paralel eşzamanlamayı engelleyin.
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
            }
        }
    }
    /**
     * Sistemin sync adapteri çağırmasını sağlayan bir nesne dönün.     
     */
    @Override
    public IBinder onBind(Intent intent) {
        /*
         * onPerformSync() metodunu çağırmak için harici işlemlere izin veren
         * nesneyi elde edin. Bu nesne, SyncAdapter yapılandırıcısı super() metodunu  
         * çağırdığında temel sınıf kodunda oluşur.
         */
        return sSyncAdapter.getSyncAdapterBinder();
    }
}

 

Çatı için gereken hesabı eklemek

Sync adapter çatısı her sync adapterinin bir hesap tipi olmasına ihtiyaç duyar. Hesap tipi değerini Doğrulayıcıyı Metadata Dosyasına Eklemek bölümünde atadınız. Şimdi, bu hesap tipini Android sisteminizde de kaydetmeniz gerekecek. Bunun için addAccountExplicity() metodunu çağırarak hesap tipini kullanan ama işe yaramayacak bir hesap ekleyin.

Bu metodunu çağırmanın en iyi yeri, uygulamanızın açılırken çağırılan onCreate() metodur. Aşağıdaki kod parçası nasıl yapılacağını göstermektedir:

public class MainActivity extends FragmentActivity {
    ...
    ...
    // Sabit değerler
    // Sync adapter'ün içerik sağlayıcısına yetkisi
    public static final String AUTHORITY = "com.example.android.datasync.provider"
    // Alan adı formatında hesap tipi
    public static final String ACCOUNT_TYPE = "example.com";
    // Hesap ismi
    public static final String ACCOUNT = "dummyaccount";
    // Instance alanları
    Account mAccount;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Boş hesap oluşturmak
        mAccount = CreateSyncAccount(this);
        ...
    }
    ...
    /**
     * Sync adapter için yeni boş bir hesap oluşturmak
     *
     * @param context The application context
     */
    public static Account CreateSyncAccount(Context context) {
        // Hesap tipini ve varsayılan hesabı oluşturmak
        Account newAccount = new Account(
                ACCOUNT, ACCOUNT_TYPE);
        // Android hesap yöneticisinin instance'ini almak
        AccountManager accountManager =
                (AccountManager) context.getSystemService(
                        ACCOUNT_SERVICE);
        /*
         * Şifre veya kullanıcı bilgisi olmadan hesap ve hesap tipi ekle
         * Eğer başarılıysa, Account nesnesini dön, değilse hata rapor et.
         */
        if (accountManager.addAccountExplicitly(newAccount, null, null))) {
            /*
             * Eğer android:syncable="true" değişkenini manifest içindeki <provider> elemanında ayarlamadıysanız,
             * context.setIsSyncable(account, AUTHORITY, 1) metodunu burada çağır.
             */
        } else {
            /*
             * Hesap mevcut ya da bazı hatalar çıktı. Bunu saklayıp rapor edin
             * ya da içerde çözün.
             */
        }
    }
    ...
}

 

Sync Adapter metadata dosyasını eklemek

Sync adapter bileşeninizi çatıya bağlamak için çatıyı, bileşeni anlatan ve ek bayrakları içeren bir metadata ile sunmalısınız. Bu metadata sync adapter'iniz için yarattığınız hesap tipini belirtir, uygulamanızla ilgili bir içerik sağlayıcıyı tanımlar, kullanıcı arayüzünün sync adapter ile ilgili bir bölümünü kontrol eder ve diğer eşzamanlama bayraklarını belirtir. Bu metadatayı özel bir XML dosyası içinde /res/xml/ yoluna koyunuz. Dosyaya istediğiniz ismi verebilirsiniz ancak genelde syncadapter.xml şeklinde adlandırılır.

Bu XML dosyası aşağıdaki özelliklere sahip tek bir XML parçası <sync-adapter> içerir:

android:contentAuthority: İçerik sağlayıcınız için yetkili URI. Eğer bir önceki ders Aracı İçerik Sağlayıcı Yaratmak'ta bir stub content provider oluşturduysanız, uygulamanızın manifestine eklediğiniz <provider> elemanı içindeki attributeandroid:authorities'e atadığınız değeri kullanabilirsiniz. Bu değer Sağlayıcıyı Manifest'te Belirtmek bölümünde detaylıca açıklanmıştır. Eğer içerik sağlayıcıdan sunucunuza sync adapter kullanarak veri aktarıyorsanız, bu değer o veri için kullandığınız URI yetkilisiyle aynı değer olmalıdır.

android:accountType: Sync adapter çatısı için gerekli hesap tipidir. Bu değer, Doğrulayıcıyı Metadata Dosyasına Eklemek bölümünde anlatıldığı gibi yetkili metadata dosyasını oluşturduğunuzda atadığınız hesap tipi değeriyle aynı olmalıdır. Ayrıca bu değer, Çatı için Gereken Hesabı Eklemekbölümündeki kod parçasında ACCOUNT_TYPE'a atanan sabit değerdir.

 

Ayar değerleri

android:userVisible: Sync adapter'in hesap tipinin görünürlüğünü belirler. Varsayılan olarak, hesap tipiyle ilgili hesap simgesi ve yazısı sistemin ayarlar bölümünde Hesaplar kategorisinde görünür vaziyettedir yani sync adapter'inizi, uygulamanıza kolaylıkla ilişkilenebilen bir hesap tipi yoksa görünmez yapmanız gerekir. Hesap tipinizi görünmez yapsanız dahi, kullanıcılarınızın sync adapter'inizi hâlâ arayüzden kontrol etmelerini sağlayabilirsiniz.

android:supportsUploading: Buluta veri yüklemenizi sağlar. Uygulamanız sadece veri indiriyorsa bunu false olarak atayın.

android:allowParallelSyncs: Sync adapter bileşeninizin birden fazla instance'ını aynı anda çalıştırmaya yarar. Eğer uygulamanız birden fazla kullanıcı hesabıyla çalışıyorsa ve kullanıcıların paralel olarak veri aktarmasını istiyorsanız bunu kullanın. Eğer birden fazla veri transferi kullanmazsanız bu bayrağın hiçbir etkisi yoktur.

android:isAlwaysSyncable: Sync adapter çatısına, sync adapteri belirlediğiniz zamanda çalıştırabileceğini gösterir. Eğer programatik olarak sync adapterinizin ne zaman çalışacağını kontrol etmek istiyorsanız, bu bayrağı false olarak ayarlayıp, requestSync() metodunu çağırarak sync adapteri çalıştırın. Bu konuda daha fazla bilgi almak için Bir Sync Adapter'i Çalıştırmak dersine bakabilirsiniz.

Aşağıdaki örnek, uydurma bir hesap kullanan ve sadece indirme yapan bir sync adapter'e ait XML'i göstermektedir.

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="com.example.android.datasync.provider"
        android:accountType="com.android.example.datasync"
        android:userVisible="false"
        android:supportsUploading="false"
        android:allowParallelSyncs="false"
        android:isAlwaysSyncable="true"/>

 

Sync Adapter'i Manifest'te belirtmek

Sync adapter bileşenini uygulamanıza ekledikten sonra, bu bileşeni kullanan izinleri istemeniz ve eklediğiniz bound service'i belirtmeniz gerekir.

Sync adapter bileşeni ağ ve cihaz arasında veri aktarımı yapan kodu çalıştırdığından, internete erişim izni istemelisiniz. Buna ek olarak, uygulamanız sync adapter ayarlarını okumak ve yazmak için izin istemelidir. Bu sayede sync adapteri programatik olarak diğer bileşenlerden kontrol edebilirsiniz. Ayrıca uygulamanızın Stub Authenticator Yaratmak dersinde yarattığınız yetkili bileşeninin kullanım iznini de istemeniz gerekir.

Bu izinleri istemek için uygulamanızın manifestinde <manifest> elemanının altına aşağıdakileri eklemeniz gerekir:

android.permission.INTERNET: Sync adapter kodunun İnternet'e erişmesine izin verir. Bu sayede cihazınıza sunucudan veri yükleme veya indirme yapabilirsiniz. Eğer bunu daha önce eklediyseniz tekrar etmeye gerek yoktur.

android.permission.READ_SYNC_SETTINGS: Uygulamanızın mevcut sync adapter ayarlarını okumasına izin verir. Örneğin, getIsSyncable() metodunu çağırmak için bu izini almanız gerekir.

android.permission.WRITE_SYNC_SETTINGS: Uygulamanızın sync adapter ayarlarını kontrol etmesine izin verir. addPeriodicSync() metodunu kullanarak periyodik sync adapter çalışması yapmak istiyorsanız bu izni almalısınız. Bu izin requestSync() metodunu çağırmak için gerekli değildir. Daha fazla bilgi almak için Bir Sync Adapter'i Çalıştırmak bölümüne bakınız.

android.permission.AUTHENTICATE_ACCOUNTS: Stub Authenticator Yaratmak eğitim içeriğinde yarattığınız yetkili bileşenini kullanmanıza izin verir.

Aşağıdaki kod parçası bu izinleri nasıl ekleyeceğinizi gösterir:

<manifest>
...
    <uses-permission
            android:name="android.permission.INTERNET"/>
    <uses-permission
            android:name="android.permission.READ_SYNC_SETTINGS"/>
    <uses-permission
            android:name="android.permission.WRITE_SYNC_SETTINGS"/>
    <uses-permission
            android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
...
</manifest>

Son olarak, çatının sync adapter ile iletişime geçmek kullandığı bound Service'i belirtmek için aşağıdaki XML'i uygulamanızın manifestinde <application> elemanının altına ekleyin:

<service
                android:name="com.example.android.datasync.SyncService"
                android:exported="true"
                android:process=":sync">
            <intent-filter>
                <action android:name="android.content.SyncAdapter"/>
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter"
                    android:resource="@xml/syncadapter" />
        </service>

<intent-filter> elemanı, actionandroid.content.SyncAdapter intenti tarafından tetiklenen ve sync adapteri çalıştırmak için sistem tarafından yollanan bir filtre koyar. Bu filtre tetiklendiği zaman sistem yarattığınız bound service'i başlatır. Bu bound service örnekte SyncService olarak belirtilmiştir. android:exportes="true" değeri uygulamanız harici işlemlerin Service'e erişmesini sağlar. android:process="sync" değeri, sisteme Service'i sync isimli, genel paylaşılmış işlemin içinde çalışmasını söyler. Eğer uygulamanızda birden fazla sync adapter varsa bu işlemi paylaşabilirler, bu da aşırı yüklemeyi azaltır.

<meta-data> elemanı sync adapter'in metadatası olan XML dosyasının ismini verir. android:name değeri, bu metadatanın sync adapter çatısı için olduğunu belirtir. android:resource elemanı metadatanın ismini belirler.

Sync adapter'in bütün bileşenlerine sahipsiniz. Bundan sonraki eğitim içeriği sync adapter çatısına, cevap ya da düzenli program olarak sync adapter'i nasıl çalıştırması gerektiğini söyleyeceksiniz.

 

Bu sayfadaki parçalar Android Open Source Project kapsamında oluşturulmuş ve paylaşılmış içeriğin küçük değişiklikler yapılmış halidir ve Creative Commons 2.5 Attribution License'ta belirlenen koşullara göre kullanılmıştır.

Bu eğitim içeriğinin orijinal hâline buradan ulaşabilirsiniz: Creating a Sync Adapter