Mobil Programlama

Android

Bir Sync Adapter'ı Çalıştırmak

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

Daha önceki eğitim içeriklerinde, veri aktarım kodunu kapsayan bir Sync Adapter bileşenini ve bu Sync Adapter'ı sisteminize bağlamak için gerekli diğer bileşenleri nasıl yaratacağınızı öğrendiniz. Bir Sync Adapter içeren uygulamayı yüklemek için her şeye sahipsiniz ancak gördüğünüz kodların hiç biri gerçekten bir Sync Adapter çalıştırmıyordu.

Sync Adapter'ınızı bir plana dayanarak ya da bir başka event'in direkt sonucu olarak çalıştırmayı denemelesiniz. Örneğin, Sync Adapter'ınızı düzenli bir plana göre çalıştırmak istiyorsunuz, bu belirli bir zaman diliminden sonra da olabilir günün belirli zamanlarında da olabilir. Aynı zamanda bellekte saklanan veride herhangi bir değişiklik olduğunda da çalıştırmak isteyebilirsiniz. Sync Adapter'ınızı bir kullanıcı aksiyonunun direkt sonucu olarak çalıştırmaktan kaçınmalısınız çünkü böyle yaparak Sync Adapter uygulama çatısının planlama özelliğinden tam yararlanamamış olursunuz. Örneğin, uygulamanıza bir yenileme düğmesi koymaktan kaçınmalısınız.

Çalışan Sync Adapter'ınız için aşağıdaki seçeneklere sahipsiniz:

  • Sunucu verisi değiştiğinde: Sync Adapter'ınızı sunucunuzdan gelen bir mesaja cevap olarak çalıştırın, bu sayede sunucu tabanlı verinin değiştiğini göstermiş olursunuz. Bu seçenek, sürekli sunucuyu yoklayarak harcayacağınız bataryayı ve performansı düşürerek veriyi güncellemenizi sağlar.
  • Cihaz verisi değiştiğinde: Cihazınızdaki veri değiştiğinde Sync Adapter'ı çalıştırın. Bu seçenek, değiştirilmiş veriyi cihazdan sunucuya yollamanızı ve bu sayede sunucunun her zaman güncel veriye sahip olduğunu güvence altına almanızı sağlar. Bu seçenek gerçekten içerik sağlayıcınızda veri tutuyorsanız doğrudan yazmanızı sağlar. Eğer aracı içerik sağlayıcı kullanıyorsanız, veri değişikliklerini tespit etmek daha zor olabilir.
  • Sistem ağ mesajı yolladığında: Android sistem TCP/IP bağlantısını açık tutan bir ağ mesajı yolladığında Sync Adapter'ı çalıştırın. Bu mesaj, ağ uygulama çatısının temel bir bölümüdür. Bu seçeneği kullanmak, Sync Adapter'ı otomatik çalıştırmanın bir yoludur. 
  • Düzenli aralıklarla: Sync Adapter'ı belirlediğiniz bir zaman aralığı geçtiğinde ya da günün belli bir saatinde çalıştırın.
  • Gerekli olduğunda: Sync Adapter'ı bir kullanıcı aksiyonunda kullanın. En iyi kullanıcı deneyimi için öncelikli olarak daha otomatik seçeneklere yönelmelisiniz. Bu sayede, batarya ve ağ kaynaklarını daha verimli kullanmış olursunuz.

Bu eğitim içeriğinin devamı, tüm bu seçenekleri daha detaylı anlatacak.

 

Sync Adapter'ı sunucu verisi değiştiğinde çalıştırmak

Eğer uygulamanız sunucudan veri aktarımı yapıyorsa ve sunucu verisi aralıklarla değişiyorsa, Sync Adapter'ı veri değişikliklerine cevap olarak indirme işlemi için kullanabilirsiniz. Sync Adapter'ı çalıştırmak için sunucunun uygulamanızdaki aBroadcastReceiver'a bir mesaj göndermesini sağlayın. Bu mesaja cevap olarak, ContentResolver.requestSync() 'i çağırarak Sync Adapter çatısına Sync Adapter'ınızı çalıştırması için sinyal yollayın.

Google Bulut Mesajlaşma (GCM), hem sunucu hem de cihaz bileşenlerini bu sistem mesajlaşması işini yapabilmesi için sağlar. Aktarımları daha güvenilir ve sürekli yoklama yönteminden daha verimli olarak yapmak istiyorsanız GCM kullanarak tetikleyebilirsiniz. Yoklama Service'in her zaman aktif olmasını beklerken, GCM sadece mesaj geldiğinde aktif olan BroadcastReceiver'ı kullanır. Belirli aralıklarla yoklama batarya gücünü güncelleme olmasa bile kullanırken, GCM sadece gerekli olduğunda mesaj gönderir.

Not: Eğer uygulamanızın yüklü olduğu tüm cihazlarda Sync Adapter'ı tetiklemek için GCM'i kullanırsanız, unutmayınız ki bütün cihazlar mesajınızı hemen hemen aynı anda alacaktır. Bu durum, Sync Adapter'ın çeşitli bölümlerinin aynı anda çalışmasına bu da sunucunun ve ağın aşırı yüklenmesine neden olur. Bundan kaçmak için Sync Adapter'ın başlama zamanının tüm cihazlar için tekil olmasını sağlayabilirsiniz.

Aşağıdaki kod parçası requestSync()'in gelen bir GCM mesajına cevabını gösterir:

public class GcmBroadcastReceiver extends BroadcastReceiver {
    ...
    // Sabitler
    // İçerik sağlayıcı yetkisi
    public static final String AUTHORITY = "com.example.android.datasync.provider"
    // Hesap tipi
    public static final String ACCOUNT_TYPE = "com.example.android.datasync";
    // Hesap
    public static final String ACCOUNT = "default_account";
    // Genişletilmiş veri için gelen Intent
    public static final String KEY_SYNC_REQUEST =
            "com.example.android.datasync.KEY_SYNC_REQUEST";
    ...
    @Override
    public void onReceive(Context context, Intent intent) {
        // GCM nesnesi intance'i almak
        GoogleCloudMessaging gcm =
                GoogleCloudMessaging.getInstance(context);
        // GCM mesajının tipini almak
        String messageType = gcm.getMessageType(intent);
        /*
         * Mesaj tipini ve mesaj içeriğini test edin.
         * GCM, genel amaçlı bir mesajlaşma sistemi olduğu için, 
         * Sync Adapter'ı çalıştırmak için gerekmeyen mesajları da 
         * alabilirsiniz.
         * Aşağıdaki kod parçası, cihazdan veri aktarımı için gerekli 
         * bayrağı test eder.
         */
        if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)
            &&
            intent.getBooleanExtra(KEY_SYNC_REQUEST)) {
            /*
             * Uygulama geliştirme çatınıza Sync Adapter'ı çalıştırması için sinyal gönderir.
             * Uygulama yükleyicinin çoktan hesabı oluşturduğunu varsayın.
             */
            ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
            ...
        }
        ...
    }
    ...
}

 

Sync Adapter'ı içerik sağlayıcı verisi değiştiğinde çalıştırmak

Uygulamanız içerik sağlayıcınızda veri depoluyorsa ve sunucuyu içerik sağlayıcınız her güncellendiğinde güncellemek istiyorsanız, uygulamanızı Sync Adapter'ı otomatik olarak güncellemesi için ayarlayabilirsiniz. Bunu yapmak için içerik sağlayıcınıza bir gözlemci bağlamanız gerekir. İçerik sağlayıcınızda veri değiştiği zaman içerik sağlayıcı uygulama çatısı gözlemciye haber verir. Gözlemci requestSync() metodunu çağırarak uygulama çatısına Sync Adapter'ı çalıştırmasını söyler.

Not: Eğer bir aracı içerik sağlayıcı kullanıyorsanız, içerik sağlayıcınızda veri depolamıyorsunuz demektir ve onChange() metodu hiç bir zaman çağrılmamıştır. Bu durumda, değişiklikleri tespit edebilecek kendi mekanizmanızı kurmalısınız. Bu mekanızma aynı zamanda veri değiştiğinde requestSync() metodunu çağırabilmelidir.

İçerik sağlayıcınız için bir gözlemci yaratmak istiyorsanız, ContentObserver sınıfını türeterek, onChange() metodunun her iki formunu da yazmanız gerekir. onChange() metodu içinde requestSync() metodunu çağırarak Sync Adapter'ınızı çalıştırın.

Gözlemciyi kaydetmek için, registerContentObserver() metodunu çağırırken argüman olarak yollamanız gerekir. Bu çağırmada aynı zamanda izlemek istediğiniz veri için bir içerik URI de göndermeniz gerekir. İçerik sağlayıcı uygulama çatısı bu izleme URI'ı ile ContentResolver.insert() metodu gibi ContentResolver metodlarıyla yollanmış içerik URI'sını karşılaştırır. Eğer bir uyum varsa ofContentObserver.onChange() metodunuz çağrılır.

Aşağıdaki kod parçası bir tablo değiştiğinde requestSync() metodu çağıran bir ContentObserver nasıl tanımlanır onu gösteriyor:



public class MainActivity extends FragmentActivity {
    ...
    // Sabitler
    // İçerik sağlayıcı şeması
    public static final String SCHEME = "content://";
    // İçerik sağlayıcı yetkilendiricisi
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // İçerik sağlayıcı tablosu için yol
    public static final String TABLE_PATH = "data_table";
    // Hesap
    public static final String ACCOUNT = "default_account";
    // Global değişkenler
    // İçerik sağlayıcının veri tablosu için bir içerik URI'ı
    Uri mUri;
    // Sağlayıcıya erişmek için içerik çözümleyici
    ContentResolver mResolver;
    ...
    public class TableObserver extends ContentObserver {
        /*
         * Gözlemlenen içerik sağlayıcı değiştiğinde çağırılan 
         * bir method tanımlayın.
         * Bu method imzası eski platformlar için uyumluluk sağlaması açısından 
         * verildi.
         */
        @Override
        public void onChange(boolean selfChange) {
            /*
             * Android platformunun 4.1 sürümünde metod imzasını çağırmak 
             * null bir URI ile mümkün.
             */
            onChange(selfChange, null);
        }
        /*
         * Gözlemlenen içerik sağlayıcı içindeki veri
         * değiştiğinde çağırılan bir metod tanımlayın.
         */
        @Override
        public void onChange(boolean selfChange, Uri changeUri) {
            /*
             * Uygulama çatısına Sync Adapter'ınızı çalıştırmasını söyleyin.
             * Arkaplan bütünlüğünü yakalamak için changeUri'ın null
             * olduğunu kabul edin.
            ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
        }
        ...
    }
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // İçerik çözümleyici nesnesini alın.
        mResolver = getContentResolver();
        // İçerik sağlayıcı veri tablosunu gösteren bir URI yaratın.
        mUri = new Uri.Builder()
                  .scheme(SCHEME)
                  .authority(AUTHORITY)
                  .path(TABLE_PATH)
                  .build();
        /*
         * İçerik gözlemleyici nesnesi oluşturun.
         * Bunun kodu sağlayıcıyı değiştirmez, dolayısıyla
         * selfChange'i "false" atayabilirsiniz.
         */
        TableObserver observer = new TableObserver(false);
        /*
         * Gözlemleyiciyi veri tablosuna kaydedin. Tablonun yolu 
         * ve bütün alt yolları gözlemciyi tetikleri.
         */
        mResolver.registerContentObserver(mUri, true, observer);
        ...
    }
    ...
}

 

Sync Adapter'ı bir ağ mesajından sonra çalıştırmak

Bir ağ bağlantısı mümkün olduğunda, Android sistem, TCP/IP bağlantısını açık tutmak için her saniye bir mesaj gönderir. Bu mesaj aynı zamanda her uygulamanın ContentResolver'ına gider. setSyncAutomatically() metodunu çağırarak, Sync Adapter'ı ContentResolver bu mesajı her aldığında çalışmasını sağlayabilirsiniz.

Sync Adapter'ınızı her ağ mesajı yollandığında çalıştırmak üzere planladığınızda, Sync Adapter'ın ağ uygun olduğunda hep çalışacak şekilde programladığınıza emin olun. Bu özelliği, her veri değişiminde veri aktarımına zorlamayacaksanız ama verinin de belirli aralıklara güncel olduğundan emin olmak istediğinizde kullanın. Benzer şekilde, bu seçeneği eğer Sync Adapter'ıniz için sabit bir planlama istemiyorsanız ama sıklıkla çalıştırmak istiyorsanız kullanın.

setSyncAutomatically(), addPeriodicSync() metodunu devre dışı bırakmadığı için, Sync Adapter'ıniz kısa zaman aralıklarında tekrar tekrar tetiklenebilir. Sync Adapter'ınızı belirli bir planda periyodik olarak çalıştırmak istiyorsanız, setSyncAutomatically() metodunu devre dışı bırakmalısınız.

Aşağıdaki kod parçası, ContentResolver'ınızı Sync Adapter'ı bir ağ mesajına cevap olarak çalıştırmak istediğinizde nasıl ayarlamanız gerektiğini gösterecek:

public class MainActivity extends FragmentActivity {
    ...
    // Sabitler
    // İçerik sağlayıcı yetkilendirmesi
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Hesap
    public static final String ACCOUNT = "default_account";
    // Genel değişkenler
    // Sağlayıcıya erişen bir içerik çözümleyicisi.
    ContentResolver mResolver;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Uygulamanız için içerik çözümleyici
        mResolver = getContentResolver();
        // Verilen hesap ve yetkilendirme için otomatik eşzamanlamayı açın.
        mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true);
        ...
    }
    ...
}

 

Sync Adapter'ı periyodik çalıştırın

Sync Adapter'ınızı çalışmalar arasında beklemek için belirli bir süre koyarak ya da günün belirli saatlerinde çalıştırarak periyodik olarak çalıştırabilirsiniz. Sync Adapter'ınızı periyodik olarak çalıştırmak, kabaca sunucunuzdaki güncelleme aralığıyla eşleşecektir.

Benzer şekilde, Sync Adapter'ı gece de çalışacak hale getirirseniz, sunucunuz bekleme durumundayken de cihazınıza veri yüklemesi yapabilirsiniz. Kullanıcıların çoğu, gece vakti cihazlarını güçte ya da fişte bırakırlar. Dolayısıyla bu vakitler uygun olur. Daha fazlası, Sync Adapter'ıniz gibi diğer görevlerle aynı zamanda çalışıyor olmaz. Bu yaklaşımı seçseniz dahi, her cihazın veri aktarımı için tetiklenme zamanının farklı olduğundan emin olmalısınız. Eğer tüm cihazlar Sync Adapter'ınızı aynı zamanda çalıştrırsa, sunucunuza ve veri ağlarına çok yüklenmiş olursunuz.

Genelde periyodik çalıştırmalar, kullanıcılarınız anlık güncellemeler istemediğinde, düzenli güncellemeler istediklerinde işe yarar. Periyodik çalışmalar, aynı zamanda güncellenmiş verinizin uygunluğu ile daha küçük Sync Adapter çalıştırmalarınızın verimliliği arasındaki dengeyi cihaz kaynaklarını aşırı kullanmadan sağlar.

Sync Adapter'ı düzenli aralıklarlar çalıştırmak için addPeriodicSync() metodunu çağırın. Bu, Sync Adapter'ınızı belirlenmiş bir zamana erişildiğinde çalıştırmak için planlar. Sync Adapter uygulama çatısı, diğer Sync Adapter uygulamalarına bağlı olduğu ve batarya verimliliğini en yükseğe çıkarmak için uğraştığı için belirlenmiş zaman birkaç saniye değişebilir. Aynı zamanda, uygulama çatısı eğer ağ uygun değilse Sync Adapter'ınızı çalıştırmayacaktır

Şunu unutmayın ki, addPeriodicSync() Sync Adapter'ı günün belirli saatlerinde çalıştırmaz. Sync Adapter'ı her gün kabaca aynı saatte çalıştırmak istiyorsanız, tekrar eden bir alarmı tetikleyici olarak kullanın. Tekrar eden alarmlar AlarmManager belgelendirmesinde detaylıca anlatılmıştır. Eğer setInexactRepeating() metodunu gün tetikleyicileri olarak kullanırsanız, başlangıç saatini rastgele seçmelisiniz ki, bütün cihazlarda aynı olmasın.

addPeriodicSync() metodu setSyncAutomatically() metodunu devre dışı bırakmaz, dolayısıyla kısa bir zaman diliminde birden çok eşzamanlama yaşayabilirsiniz. Aynı zamanda sadece birkaç Sync Adapter kontrol bayrağı addPeriodicSync() metoduna eklenmesi için izin verilmiştir. İzin verilmeyen bayraklar addPeriodicSync() metodunun belgelendirmesinde anlatılmıştır.

Aşağıdaki kod parçası Sync Adapter çalıştırmalarını nasıl planlamanız gerektiğini anlatır:



public class MainActivity extends FragmentActivity {
    ...
    // Sabitler
    // İçerik sağlayıcı yetkilendirmesi
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Hesap
    public static final String ACCOUNT = "default_account";
    // Aralık sabitlerini tanımlayın
    public static final long SECONDS_PER_MINUTE = 60L;
    public static final long SYNC_INTERVAL_IN_MINUTES = 60L;
    public static final long SYNC_INTERVAL =
            SYNC_INTERVAL_IN_MINUTES *
            SECONDS_PER_MINUTE;
    // Genel değişkenler
    // Sağlayıcıya erişmesi için içerik çözümleyici
    ContentResolver mResolver;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // İçerik çözümleyici
        mResolver = getContentResolver();
        /*
         * Periyodik eşzamanlama
         */
        ContentResolver.addPeriodicSync(
                ACCOUNT,
                AUTHORITY,
                Bundle.EMPTY,
                SYNC_INTERVAL);
        ...
    }
    ...
}

 

Sync Adapter'ı ihtiyaç olduğunda çalıştırmak

Sync Adapter'ı bir kullanıcı isteğine cevap olarak çalıştırmak, çalışan bir Sync Adapter için en az tercih edilen stratejidir. Uygulama çatısı, Sync Adapter'leri plana göre çalıştırdığında, özel olarak batarya gücünü korumak için dizayn edilmiştir. Veri değiştiğinde cevap olarak eş zamanlama işi başlatmak batarya gücü verimliliğini etkiler, çünkü güç yeni veriyi almak için kullanılır.

Karşılaştırma yaptığımızda, kullanıcılara eşzamanlamayı ihtiyaç olduğunda yapmalarını sağlamak bunu kendi kendine yapabilmeleri demektir. Bu da ağ ve güç kullanımı adına verimsizlik demektir. Aynı zamanda ihtiyaç olduğunda eşzamanlama yapmak kullanıcılara veri değişimi olmadığında dahi eş zamanlama yapabilmeleri fırsatını verir. Genelde uygulamanız eşzamanlamayı tetiklemek için başka sinyaller kullanır ya da belirli aralıklara kendiliğinden olması için planlar.

Yine de ihtiyaç olduğunda Sync Adapter çalıştırmak istiyorsanız, Sync Adapter bayraklarını elle çalıştırma için ayarlayın ve ContentResolver.requestSynv() metodunu çağırın.

Aşağıdaki bayraklar bunun içindir:

  • SYNC_EXTRAS_MANUAL: Elle eşzamanlamaya zorlar. Sync Adapter uygulama çatısı, setSyncAutomatically() metodunun ayarladığı bayraklar gibi mevcut ayarları reddeder.
  • SYNC_EXTRAS_EXPEDITED: Eşzamanlamanın anında çalışması için zorlar. Bunu ayarlamazsanız, sistem bir eşzamanlama isteğini çalıştırmak için birkaç saniye bekleyebilir çünkü batarya kullanımını kısa zamanda çok gelen istekler için planlama yapmaya ayırır.

Aşağıdaki kod parçası requestSynv() metodunu bir düğmeye basıldığında çalıştırmak için ne yapmanız gerektiğini anlatır:



public class MainActivity extends FragmentActivity {
    ...
    // Sabitler
    // İçerik sağlayıcı yetkilendirmesi
    public static final String AUTHORITY =
            "com.example.android.datasync.provider"
    // Hesap tipi
    public static final String ACCOUNT_TYPE = "com.example.android.datasync";
    // Hesap
    public static final String ACCOUNT = "default_account";
    // Instace alanları
    Account mAccount;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        /*
         * Geçici hesap oluşturun. CreateSyncAccount için kod 
         * Sync Adapter oluşturmak dersinde işlendi.
         */

        mAccount = CreateSyncAccount(this);
        ...
    }
    /**
     * requestSync() çağırarak bir düğme tıklamasına cevap vermek. Bu bir 
     * asenkron işlemdir.
     *
     * Bu metod layout'un XML dosyasına yenileme düğmesi olarak eklendi.
     * 
     *
     * @param v Metod çağırımıyla etkileşimli View.
     * Bu örnekte, bu çağırışım bir düğme.
     */
    public void onRefreshButtonClick(View v) {
        ...
        // Bundle içine koyarak ayar bayraklarını göndermek.
        Bundle settingsBundle = new Bundle();
        settingsBundle.putBoolean(
                ContentResolver.SYNC_EXTRAS_MANUAL, true);
        settingsBundle.putBoolean(
                ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        /*
         * Varsayılan hesap için eş zamanlama isteği, yetkilendirme ve 
         * elle eşzamanlama ayarları.
         */
        ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
    }

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 özgün haline buradan ulaşabilirsiniz: Running a Sync Adapter