Windows 8’de Arka Plan Görevleri – Detaylar

   Sizlere en son Windows 8’de arka plan görevlerinden bahsetmiştim. Daha çok bir giriş ve mimarisel tanıtımı amaçladığım önceki yazım ardından, sizlerden de aldığım geri bildirimler doğrultusunda, bir devam yazısıyla kod örnekleri paylaşmanın doğru olacağına karar verdim. Eğer konuya doğrudan bu makalemle başladıysanız öncelikle “Windows 8’de Arka Plan Görevleri” makalemi okuyarak konu hakkında daha detaylı bilgi sahibi olmanızı tavsiye ederim. Bu makalemde birlike Windows 8’deki ilk arka plan görevimizi oluşturarak “Merhaba Dünya” derken dikkat etmemiz gereken detayları da öğreneceğiz.

   Windows 8’de en temel haliyle bir arka plan görevi iki bileşene sahip olmalı;

  • Arka plan görevini yapacak olan sınıf(lar)
  • Bu arka plan görevini yapan sınıf(lar)ı sisteme kaydedecek olan ve ana uygulamamızda yer alan kod parçacığı

   Arka plan görevimizi gerçekleştirecek olan sınıfımızla ilgili ilk isterimiz Windows.ApplicationModel.Background isim uzayı altında yer alan IBackgroundTask arayüzüne sahip olmasıdır;

using Windows.ApplicationModel.Background;

namespace Enterprisecoding.TaskOrnegi.Task {
    public sealed class ArkaPlanGorevi : IBackgroundTask {

        public void Run(IBackgroundTaskInstance taskInstance) {
            // Gerçekleştirilecek olan işe dair kodlar
            // buraya gelmeli
        }
    }
}

   Yukarıda da görebileceğiniz gibi oldukça basit bir arayüz olan IBackgroundTask arayüzü bizden sadece IBackgroundTaskInstance türünden bir parametre kabul eden bir Run metodu beklemektedir. Arka planda çalışmasını istediğimiz göreve dair kodlar işte bu Run metodu içerisinde yer alacaktır. Arka plan görevleri bir exe tarafından, varsayılan olarak BackgroundTaskHost.exe, çalıştırılacağı için yüklenebilmeleri için bir dll içerisinde bulunmalıdırlar. Bu arayüz ve dolayısıyla da arka plan görevleri hakkındaki detaylara inmeden önce hazır başlamışken bir de bu görevi sisteme nasıl kaydedebileceğinizi sizlerle paylaşayım;

BackgroundTaskBuilder builder = new BackgroundTaskBuilder {
    Name = "Örnek Arka Plan Görevi",
    TaskEntryPoint = "Enterprisecoding.TaskOrnegi.Task.ArkaPlanGorevi"
};

IBackgroundTrigger trigger = new TimeTrigger(15, false);
builder.SetTrigger(trigger);
IBackgroundTaskRegistration task = builder.Register();

  Arka plan görevini sisteme kaydetmek için kullandığımız BackgroundTaskBuilder sınıfı bizden 3 temel girdiyi girmemizi isteyecektir;

  • Arka plan görevinin adı. Bu bilgi son kullanıcının görevi diğerlerinden ayırt edebilmesini sağlayacağı için açıklayıcı bir değere sahip olmalıdır
  • Çalıştırılacak olan arka plan görevinin tanımlı olduğu sınıf tam adı. Bu değer arka plan sınıfının sistem tarafından ilklendirilerek çalıştırılması için kullanılacağından biraz önce oluşturduğumuz ve IBackgroundTask  arayüzünden türeyen sınıfımızın tam adı verilmeli.
  • Arka plan görevinin hangi durumlarda tetikleneceğini dair tetikleme bilgisi. Bir önceki makalemde sizlerle paylaşmış olduğum ve bir arka plan görevinin çalışmaya başlamasına neden olacak durumlardan hangisinin kullanılmak istendiğine dair bilgi. Yukarıdaki örnekte her 15 dakikada bir tetiklenmesi için bir zaman tetiklemesi tanımlanmıştır. Tetikleyici seçerken dikkat etmeniz gereken bir nokta UserPresent, UserAway, ControlChannelReset ve SessionConnected tetikleme türlerinin sadece kilit ekranında yer alan uygulamalarca kullaılabildiğidir. Aksi takdirde bu tetikleme türleri kullanıldığında “erişim reddedildi(access denied) hatası alınacaktır.

   Opsiyonel olarak bu arka plan görevinin tetiklenmesi sonrası başlaması için bir koşul da verebilmeniz mümkün. Aşağıdaki örnekte tanımladığımız arka plan görevimiz her 15 dakikada bir; ama sadece internet bağlantısı olduğunda çalışacaktır;

BackgroundTaskBuilder builder = new BackgroundTaskBuilder {
    Name = "Örnek Arka Plan Görevi",
    TaskEntryPoint = "Enterprisecoding.TaskOrnegi.Task.ArkaPlanGorevi"
};

IBackgroundTrigger trigger = new TimeTrigger(15, false);
builder.SetTrigger(trigger);
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
IBackgroundTaskRegistration task = builder.Register();

   Bu örnekte olduğu gibi arka plan görevimizin çalışması için gerekli koşulları da tanımlayarak uygun koşullar oluşmadığında gereksiz işlemlerle hem vakit kaybının hem de sistem kaynaklarının gereksiz kullanımının önüne geçebiliriz.

   İsterseniz bir arka plan görevinin çalışması için birden fazla koşul da verebilirsiniz. Bunun için tek yapmanız gereken her bir koşul tanımı için BackgroundTaskBuilder  içerisindeki AddCondition metodunu çağırmanız. Ardından BackgroundTaskBuilder  içerisindeki Register metodu ile tek kalemde kayıt işlemini gerçekleştirebilirsiniz. Öte yandan benzer bir mantık tetikleyiciler için geçerli değildir. Her bir tetikleyici için yukarıdaki işlemin ayrı ayrı tekrarlanması gereklidir.

   BackgroundTaskBuilder  içerisindeki Register metodu ile arka plan görevinin kaydını gerçekleştirdiğimizde bize IBackgroundTaskRegistration arayüzüne sahip bir nesne gelecektir. İsterseniz bu nesneyi kullanarak Progress olayı yardımıyla görevin durumu hakkında bilgi alabileceğiniz gibi Completed olayı yardımıyla sonlanıp sonlanmadığını da takip edebilirsiniz. Arka plan görevinin daha fazla tetiklenmesini istemezseniz Unregister metodu yardımıyla sistem kaydını silebilirsiniz. Progress ve Completed olay bildirimlerini dinliyorsanız her zaman için uygulamanızın yaşam döngüsünü aklınızda tutmanız gerekli. Eğer ilgili olan bildirimi uygulamanız askıda durumundayken geldiyse bildirimi yeniden çalışıyor durumuna geçtiğinde alacaktır. Öte yandan eğer bildirim uygulamanız çalışmıyor durumunda iken gelirse bu durum size iletilmeyecektir. Böylesi bir durumda veri kaybı yaşamak istemiyorsanız ApplicationData ya da benzeri bir yöntemle veriyi saklamanız gerekecektir.

   Ok, BackgroundTaskBuilder yardımıyla arka plan görevini sisteme kaydettik ve bu göreve Register metodunun sonucu olarak iletilen nesne sayesinde ulaşabiliyoruz. Peki ya uygulamamız herhangi bir sebeple sonlanacak olursa??! Bu durumda oluşturduğumuz görevlere ait bilgiler daha fazla hafızada bulunmayacaktır, peki bu bilgilere nasıl ulaşabiliriz? Tabi ki bu senaryo da sistem tasarımı sırasında unutulmamış, BackgroundTaskRegistration.AllTasks yardımıyla uygulamanızca kaydı yapılmış tüm arka plan görevlerine istediğiniz zaman ulaşabilirsiniz. Unutmayın, bir arka plan görevini sisteme bir defa kaydetmeniz yeterli olacaktır. Her defasında yeniden kaydetmenize gerek yok. Öte yandan Progress ve Completed olay bildirimlerinden haberdar olmak için uygulamanızın her yeniden başlatılmasında yeniden ilgili olay bildirimini dinlemeye başlamanız gerekli;

foreach (var arkaPlanGorevi in BackgroundTaskRegistration.AllTasks) {
    arkaPlanGorevi.Value.Progress += OnProgress;
    arkaPlanGorevi.Value.Completed += OnCompleted;
}

  Arka plan görev kaydı hakkındaki bu bilgiler ardında tekrar görev sınıfımıza geri dönelim. Makalemin başlarında da bahsettiğim gibi arka plan görevimiz Run metodu içerisinde gerçekleşmektedir ve Windows 8 varsayılan olarak Run metodu sonlandığında arka plan görevinin de sonlandığını kabul etmektedir. Öte yandan eğer Run metodu içerisinde asenkron bir işlem başlattıysanız işlemizin henüz sonlanmadan uygulamanız Run metodundan çıkabilir. Böylesi bir durumda Windows 8’in arka plan görevinin sonlandığını düşünerek tüm görevi hafızadan kaldırması görevin eksik/hatalı kalmasına neden olacaktır. Böylesi bir senaryoda asenkron işlemleriniz tamamlanana kadar görevin bitmediği bir şekilde Windows 8’e bildirmeniz gerekli. İşte bu amaçla kullanılmak üzere bizlere BackgroundTaskDeferral sınıfı sunulmuştur. Run metodu içerisinde herhangi bir asenkron işlemi başlatmanız durumunda aşağıdaki şekilde bir BackgroundTaskDeferral örneği alarak işleminiz sonlandığında bu nesnenin Complete metodunu çağırmalısınız.

BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

    Bu kodu makalemin başında verdiğim örnek görev sınıfı içerisine koyduğumuzda kodumuz aşağıdaki gibi olacaktır;

using Windows.ApplicationModel.Background;

namespace Enterprisecoding.TaskOrnegi.Task {
    public sealed class ArkaPlanGorevi : IBackgroundTask {

        public async void Run(IBackgroundTaskInstance taskInstance) {
            BackgroundTaskDeferral erteleme = taskInstance.GetDeferral();

            await BirIsMantigiMetoduAsync();

            erteleme.Complete(); 
        }
    }
}

   Arka plan görevleri ile ilgili olarak dikkat edilmesi gereken bir diğer nokta da görevin her an iptal edilebileceğidir. İptal işlemi ana uygulamanızdaki bir iş mantığının sonucunda olabileceği gibi işletim sistemince verilen bir karar da olabilir. Örnek vermek gerekirse; Bakım Tetiklemesi (Maintenance Trigger) ile başlatılan bir arka plan görevi cihazın fişten çekilmesiyle birlikte işletim sistemince iptal edilecektir. İşletim sistemi, herhangi bir sebeple iptal edilen bir arka plan görevinin sonlanmasını 5 saniye bekleyecektir. 5 saniye içerisinde sonlanmayan bir arka plan görevi ise işletim sistemince kapatılacaktır. Dolayısıyla da arka plan görevinizin işlemlerini sağlıklı olarak yerine getirebilmesi, herhangi bir veri kaybı yaşanmaması adına görevin iptalini dinlemesi ve iptal isteğine 5 saniye içerisinde yanıt vererek sonlanması önemlidir. Herhangi bir arka plan görevi iptal isteğini Run metoduyla gelen IBackgroundTaskInstance nesnesi içerisindeki Canceled olayını dinleyerek öğrenebilir;

taskInstance.Canceled += OnCanceled;

   Yukarıda sizlerle paylaştığım detaylar ardından bir arka plan görevi oluşturduğunuzda unutmamız gereken son bir ayrıntı da uygulamanız içerisinde bir arka plan görev tanımı bulunduğunu uygulamanızın manifest dosyasında belirtirek kurulum sırasında son kullanıcının bilgilendirilerek gerekli izinlerin verilmesini sağlamaktır.

Uygulamanız içerisinde bir arka plan görev tanımı bulunduğunu uygulamanızın manifest dosyasında belirtilmelidir

 

   Bu tanımlama işlemi her bir arka plan görevi için yapılmalıdır.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

3 yorum

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir