Android Servisleri
Servis nedir?
Servis, arka planda çalışan ve kullanıcıyla her hangi etkileşime girmeyen bir bileşendir.Bir servis kullanıcıya arayüzüne sahip olmadığı gibi bir activity’nin lifecycle’ına bağlı değildir.
Servisler veri kontrolu,intenet indirmeleri, veri işleme,içerik sağlayıcıları güncelleme gibi uzun vadede çalışan tekrarlı ve sürekli çalışmaya ihtiyaç duyan işlemler için kullanılır.
Servislerin görünmez halde olan ya da aktif halde olmayan activitylere nazaran önceliğe sahiptir.Bu sebeple Android işletim sisteminin bu işlemleri sonlandırması daha az görülür.
Ayrıca sistem kaynağı yetersizliğinde sonlandırılan bir servis tekrar başlatılması için yapılandırılabilir.
Bir servise arkaplanda çalışan bir activity ile aynı önceliği atamak da mümkündür.Bu gibi durumda,ilgili servis için görünür bir notification gereklidir.Bu durum da müzik player gibi uygulamalarda sık sık kullanılır.
Servisler ve Arkaplan İşlemleri
Bir servis ,uygulamanın Main Thread’inde aynı işlemde varsayılan olarak default olarak çalışır.Bu sebeple arkaplanda asenkronize işlem yapmak zorundasınız.Bir servis uygulamasında ortak kullanılan pattern; işlemleri başlatacak ve bitirecek bir Threadi servis içerisinde yaratıp çalıştırmaktır.
Platform Servisi ve Custom Servisler
Android platformu önceden tanımlanış servisleri çalıştırır ve bunları bize sunar.Ve her android uygulaması doğru izinler kullanarak bu servisleri kullanabilir.getSystemService() metodu ile bunlara ulaşılabilir.Bu servislere ulaşmak için Context sınıfı bir çok constant tanımlar.
Ayrıca Android platformu sizlere kendi custom servisinizi yazma olanağı da sağlar.
Custom Servis Tanımlama ve Başlatma
Custom servisler diğer Android bileşenlerinden başlatılırlar.(Activityler,Broadcast Receiverlar,Diğer servisler.)
Custom Servis Tanımlama
Uygulama ve tanımlama
Bir servis Manifest.xml dosyasında tanımlanmalıdır.Ve tanımlanacak sınıf Service sınıfından extend edilmelidir.
Aşağıdaki kodlar bir servis tanımlanmasının örneğini gösteriyor.
Bir Servisi Başlatmak
Bir servis bileşeni(Service,Receiver,Activity) startService(intent) metodu ile bir servisin faaliyete geçmesini tetikleyebilir.
Alternatif olarak bir servis bindService() metodu çağrılarak da başlatılabilir.Bu metod direk olarak servis ile iletişime geçmenize izin verir.Bu konuya daha sonra açıklı kgetireceğiz.
Eğer startService(intent) metodu çağrıldıysa ve servis henüz başlamadıysa, servis nesnesi yaratılır ve servisin onCreate() metodu çağrılır.startService(intent) metodu çağrıldığında intent nesnesini gönderir.
Servis çalışır haldeyken startService(intent) metodu çağrıldıysa, servisin onStartCommand() metodu çağrılır.
Bu yüzden onStartCommand() metodu bir kaç kere çağrılabilir,bu sebeple bu birkaç kere çağrılma işlemine karşı servis onStartCommand() metodunu hazırlaması gerekir.
Peki ya bu metod kodunuz içinde bir kaç kez çağrılırsa? Endişelenilmesi gerek bir durum oluşur mu ? Hayır.bu metod main thread’de android sistemi tarafından çağrılır.Bir servis sadece bir kez başlar istediğimiz kadar startService() metodunu çağırabiliriz.
Servisin Tekrar Başlatılması
onStartCommand() metodu çağrıldığında ir integer değer döndürür.Bu değer android platformu bu servisi sonlandırdığında kullanılacak değerdir.En çok kullanılan 3 tekrar başlatma seçeneği.
Service.START_STICKY :
Eğer servis sonlandırılırsa tekrar başlatılır.Kendi durumunu yöneten servisler için kullanılır.
Service.START_NOT_STICKY:
Servis tekrar başlatılmaz.Zaten periyodik olarak tetiklemeli servislerde kullanılır.
Service.START_REDELIVER_INTENT:
Service.Start_sticky ile çok benzerdir fakat orjinal intent onStartCommand metoduna tekrar iletilir.
Servisin başlayıp başlamadığını Intent.getFlags() metodu ile kontrol edilebilir.
Servisi Durdurmak
Bir servisi stopService() metodu çağrılarak durdurabilirsiniz.Servisi kaç kere startService(intent) ile çağırmış olursanız olun, bir kere stopService() çağrıldığında servis durdurulur.
Bir servis stopSelf() metodu çağrılarak kendini durdurabilir.Genellikle bu servis işini bitirdiğinde kullanılır.
Servisleri Bağlama(Binding Services)
Servislere Activitylerden Bağlanma
Bir activity servis ile iletişime geçmek istiyorsa , bindService() metodunu kullanarak servisi başlatabilir.
bindService() metodu parametre olarak ServiceConnection nesnesi alır.Servisin onBind() metodu ,ServiceConnection’a IBinder nesnesi döndürür.Bu IBinder nesnesi activity tarafından servis ile haberleşmede kullanılır.Daha sonra,Bağlama işlemi bittiğinde, servisteki onStartCommand() metodu çağrılır.
Local Servis Binding
Eğer servis activity ile aynı işlende çalışıyorsa, çalışılan activity’e servis objesini döndürmek mümkündür.Bu durum, activity’nin servisin içindeki metodları direlk olarak çağırmasına olanak sağlar.Bunun örneği ileride incelenecektir.
Ayrı İşlemlerdeki Servisler(Services in seperate Processes)
Bir servisi kendi işleminde çalıştırma
Servisinizi ayrıca bireysel işlemlerde özelleştirebilirsiniz
android:process=”:process_description”
android:process=”:process_description”
Burdaki isimden önce gelen iki nokta bize şunu söyler:”Bu servis tanımlandığı uygulama özel bir servistir.”.Eğer iki nokta olmasa idi bu servis global bir servis oluyordu ve bu servis diğer android uygulamaları tarafından kullanılabilirdi.
Servisi kendi process’i içerisinde çalıştırmak uzun çalışma operasyonları gerektiren servislerde uygulanın çalışmasını bloklamayacaktır.Fakat bir servis kendi process’inde çalışsa bile network işlemlerini asenkronize yapmak zorundadır çünkü Android Main Thread işlem sürecinde Network işlemlerine izin vermemektedir.
Servislerle iletişim(Communication with Services)
İletişim Seçenekleri
Activitylerin servislerle ya da servislerin Activitylerle iletişim kurmasının bir çok yolu vardır.Bu bölümde bu olayı yaparken önerilen ve mümkün olanları tartışıp inceleyeceğiz.
Intent Verisi Kullanmak(Using Intent Data)
Basit bir senaryoyla anlatılmak istenirse,Servis başlatılan android bileşenincen bir intent verisi alır ve bunu işler.Herhangi bir bildirim gerekli değildir.Örnek olarak, bi servisin Content Provider’ı update etmesi verilebilir.Activity’e Content Provider tarafından haber verilir.Serviste extra bir adıma ihtiyaç yoktur.
Receiver Kullanmak(Using Receiver)
Ayrıca iletişim için yayın alıcılar(Broadcast Receivers) kullanılabilir.Servis bir broadcast yayınlar ve Activity içerisinde tanımlanmış Broadcast receiver bu broadcast’i alır,işler ve bir sonuç döndürür.
Bu iletişim şekli aşağıda şema ile gösterilmiştir.
Yerel servise Activity Bağlanması
Eğer bir servis Activity ile aynı işlemde başladıysa ,bu activity servise direk olarak bağlanabilir.Bu yol,servis ile activity arasında hızlı bir iletişim katmanı oluşturmak için en verimli ve basit yoldur.
Bu yerel servisler için çalışır.
Handler ve ResultReceiver veya Messenger
Eğer bir service activity ile geri iletişim kurması gerekiyorsa Servis aldığı intent data ile Messenger tipinde nesne kullanarak activity ile tekrar iletişim kurabilir.Eğer Messenger, activity içerisindeki Handler ile bağlanmışsa, Servis ,Message tipinde nesneyi activitye gönderebilir.
Messenger sınıfı başka bir işleme aktarılabilir.Yani bunu kullanarak Activity’deki Handler’a mesajlar gönderebilirsiniz.
Messenger sınıfı ayrıyetten getBinder() Metodu ile Activity’e bir Messenger göndermeye izin verir.Bu nedenle Activity servise mesajlar gönderebilir.
Bu durum ise yerel ve kendi işleminde çalışan servislerde çalışır.
Servislerde daha fazlası…
Tek kullanımlıklar için IntentService
Servis sınıfınısı IntentService sınıfından extend ederek de bir servis sınıfı yaratabilirsiniz.IntentService sınıfı arkaplanda belirli görevleri uygulamak için kullanılır.Bir kere olur ve IntentService kend kendini sonlandırır.Buna örnek olarak Download işlemleri verilebilir.
Servis Kullanımı ve Servis iletişimi
Aşağıdaki örnek bir activityden butona tıklama ile internetten dosya indirme işlemini servis ile nasıl yapacağımızı gösterecek.İndirme işlemi tamamlandığında broadcast yayın yapacak ve broadcast receiver bu yayını alıp kullanıcıya indirme işlemi ile ilgili bilgileri verecek.
Bu alıştırmada IntentService sınıfı kullanılacak,çünkü bu sınıf arkaplan işlemlerini otomatik kendisi hallediyor.
Yeni bir proje oluşturun.
Ve servis için aşağıdaki class’ı oluşturun.
Bu oluşturduğumuz sınıfı AndroidManifest.xml de belirtmemiz gerekiyor.Ayrıca Manifestimizde external depolamaya yazma iznini ve internete erişim iznini istememiz gerekiyor.Sonuç olarak Manifest.xml Dosyası şu şekilde olması gerekiyor.
Activity’nizin Layout dosyası aşağıdaki gibi değiştirin.
ServiceTest sınıfımızı aşağıdaki gibi değiştirin.
Eğer örneği çalıştırıp indir butonuna basarsanız.İndirme işlemi Servis tarafından yapılacaktır.Tamamlandığında Kullanıcı arayüzü güncellenip Toast mesajı ile sizi bilgilendirecektir.
Şimdi projenin çalışma mantığına yakından bakalım.
Butona tıkladığımızda bir intent nesnesinin içine dosya ismini ve dosyanın URL’ini startService() metodu ile servise gönderiyoruz.Servis,onHandleIntent() metodunu çağırıyor ve bu gelen intentin içerisindeki dosya ismini ve URL bilgisini kullanılmak üzere değerlere atıyor.Ve dosyayı indirmeye başlıyor.İndirme işlemi tamamlandığında publishResults() metodu içerisinde sendBroadcast() methodu çağrılıyor.Bu broadcast yayını yapmamızın amacı servisimizin işini bitirdiğini ve bundan haberdar olmak isteyenler bu bilgileri alması gerektiğini söylemektir.
ServiceTest sınıfında oluşturulan BroadcastReceiver’ımızın onReceive() metodu bundan haberdar oluyor ve bu gelen bilgileri bir Bundle referansına koyuyor ve handleResult() metodu çağrılıyor.HandleResult() metodunda ise indirme işleminin durumu kontrol edilip kullanıcı arayüzü güncelleniyor ve kullanıcıya son durum hakkında bilgi veriliyor.