Hizmetlere genel bakış

Service, arka planda uzun süreli işlemler yapabilen bir uygulama bileşenidir. Bir kullanıcı arayüzü sağlamaz. Bir hizmet, başlatıldıktan sonra kullanıcı başka bir uygulamaya geçtikten sonra bile bir süre daha çalışmaya devam edebilir. Ek olarak, bir bileşen etkileşim kurmak ve hatta işlemler arası iletişim (IPC) gerçekleştirmek için bir hizmete bağlanabilir. Örneğin, bir hizmet arka planda ağ işlemlerini gerçekleştirebilir, müzik çalabilir, dosya G/Ç işlemi gerçekleştirebilir veya bir içerik sağlayıcıyla etkileşim kurabilir.

Dikkat: Bir hizmet, barındırma işleminin ana iş parçacığında çalışır. Hizmet kendi iş parçacığını oluşturmaz ve aksini belirtmediğiniz sürece ayrı bir süreçte çalışmaz. Uygulama Yanıt Vermiyor (ANR) hatalarını önlemek için tüm engelleme işlemlerini hizmet içindeki ayrı bir iş parçacığında çalıştırmanız gerekir.

Hizmet Türleri

Üç farklı hizmet türü şunlardır:

Ön plan

Bir ön plan hizmeti, kullanıcının fark edebileceği bir işlem gerçekleştirir. Örneğin, bir ses uygulaması, ses parçası çalmak için ön plan hizmetini kullanır. Ön plan hizmetlerinde bir Bildirim gösterilmelidir. Ön plan hizmetleri, kullanıcı uygulamayla etkileşimde bulunmasa bile çalışmaya devam eder.

Bir ön plan hizmeti kullandığınızda, kullanıcıların hizmetin çalıştığının farkında olması için bir bildirim görüntülemeniz gerekir. Hizmet durdurulmadığı veya ön plandan kaldırılmadığı sürece bu bildirim kapatılamaz.

Uygulamanızda ön plan hizmetlerini nasıl yapılandıracağınız hakkında daha fazla bilgi edinin.

Not: WorkManager API, görevleri planlamanın esnek bir yolunu sunar ve gerekirse bu işleri ön plan hizmeti olarak çalıştırabilir. Çoğu durumda, WorkManager'ın doğrudan ön plan hizmetlerinin kullanılması tercih edilir.

Genel bilgi
Arka plan hizmeti, kullanıcının doğrudan fark etmediği bir işlem gerçekleştirir. Örneğin, bir uygulama, depolama alanını küçültmek için bir hizmet kullandıysa bu hizmet genellikle bir arka plan hizmeti olur.

Not: Uygulamanız API düzeyi 26 veya üstünü hedefliyorsa sistem ön planda değilken arka plan hizmetlerinin çalıştırılmasına kısıtlamalar uygular. Örneğin, çoğu durumda konum bilgilerine arka plandan erişmemeniz gerekir. Bunun yerine WorkManager kullanarak görevleri planlayın.

Bağlı
Bir uygulama bileşeni bindService() yöntemini çağırarak hizmete bağlandığında hizmet bağlıdır. Bağlı hizmet, bileşenlerin hizmetle etkileşim kurmasına, istek göndermesine, sonuç almasına ve hatta işlemler arası iletişim (IPC) ile işlemler genelinde yapmasına olanak tanıyan bir istemci-sunucu arayüzü sunar. Bağlı bir hizmet, yalnızca başka bir uygulama bileşeni ona bağlı olduğu sürece çalışır. Birden çok bileşen hizmete aynı anda bağlanabilir ancak bu bileşenlerin tümünün bağlantısı kaldırıldığında hizmet kaldırılır.

Bu belgede genellikle başlatılan ve bağlanan hizmetler ayrı ayrı anlatılsa da hizmetiniz her iki şekilde de çalışabilir. Hizmetiniz başlatılabilir (süresiz olarak çalışacak şekilde) ve bağlamaya izin verilebilir. Bu, birkaç geri çağırma yöntemini uygulayıp uygulamamanızla ilgilidir: bileşenlerin başlatmasına izin vermek için onStartCommand() ve bağlamaya izin vermek için onBind().

Hizmetinizin başlatılmış, bağlanmış veya her ikisi birden olmasına bakılmaksızın, herhangi bir uygulama bileşeni hizmeti (ayrı bir uygulamadan bile) herhangi bir bileşenin bir etkinliği kullanabileceği şekilde (Intent ile başlatarak) kullanabilir. Ancak, manifest dosyasında hizmeti gizli olarak beyan edebilir ve diğer uygulamalardan erişimi engelleyebilirsiniz. Bu konu, Manifest'te hizmeti bildirme bölümünde daha ayrıntılı olarak ele alınmaktadır.

Hizmet ve iş parçacığı arasında seçim yapma

Hizmet, kullanıcı uygulamanızla etkileşime geçmediğinde bile arka planda çalışabilen bir bileşendir. Bu nedenle, yalnızca ihtiyacınız olduğunda bir hizmet oluşturmalısınız.

Ana iş parçacığınızın dışında, ancak yalnızca kullanıcı uygulamanızla etkileşimde bulunurken gerçekleştirmeniz gerekiyorsa bunun yerine, başka bir uygulama bileşeni bağlamında yeni bir iş parçacığı oluşturmanız gerekir. Örneğin, yalnızca etkinliğiniz yayınlanırken müzik çalmak istiyorsanız onCreate() ürününde bir ileti dizisi oluşturabilir, onu onStart() ürününde çalıştırmaya başlayabilir ve onStop() konumunda durdurabilirsiniz. Ayrıca, geleneksel Thread sınıfı yerine java.util.concurrent paketindeki veya Kotlin eş yordamlarındaki iş parçacığı havuzlarını ve yürütücüleri de kullanabilirsiniz. Yürütmeyi arka plan iş parçacığına taşıma hakkında daha fazla bilgi için Android'de iş parçacığı oluşturma dokümanına bakın.

Kullandığınız hizmet varsayılan olarak uygulamanızın ana iş parçacığında çalışmaya devam eder. Bu nedenle, yoğun işlemler veya engelleme işlemleri yapıyorsa hizmet içinde yeni bir iş parçacığı oluşturmanız gerekir.

Temel bilgiler

Hizmet oluşturmak için Service alt sınıfı oluşturmanız veya mevcut alt sınıflarından birini kullanmanız gerekir. Uygulamanızda, hizmet yaşam döngüsünün temel unsurlarını işleyen bazı geri çağırma yöntemlerini geçersiz kılmanız ve uygun durumlarda bileşenlerin hizmete bağlanmasını sağlayan bir mekanizma sağlamanız gerekir. Bunlar, geçersiz kılmanız gereken en önemli geri çağırma yöntemleridir:

onStartCommand()
Başka bir bileşen (ör. etkinlik) hizmetin başlatılmasını istediğinde sistem bu yöntemi startService() yöntemini çağırarak çağırır. Bu yöntem yürütüldüğünde hizmet başlatılır ve arka planda süresiz olarak çalışabilir. Bunu uygularsanız stopSelf() veya stopService() numarasını arayarak işi tamamlandığında hizmeti durdurmak sizin sorumluluğunuzdadır. Yalnızca bağlama sağlamak istiyorsanız bu yöntemi uygulamanız gerekmez.
onBind()
Başka bir bileşen hizmete bağlanmak (ör. TBG gerçekleştirmek) istediğinde sistem bindService() yöntemini çağırarak bu yöntemi çağırır. Bu yöntemi uygularken istemcilerin hizmetle iletişim kurmak için kullanabileceği bir IBinder döndürerek arayüz sağlamanız gerekir. Bu yöntemi her zaman uygulamanız gerekir; ancak, bağlamaya izin vermek istemiyorsanız null değerini döndürmeniz gerekir.
onCreate()
Sistem bu yöntemi, hizmet ilk oluşturulduğunda (onStartCommand() veya onBind() yöntemini çağırmadan önce) tek seferlik kurulum prosedürleri gerçekleştirmek için çağırır. Hizmet zaten çalışıyorsa bu yöntem çağrılmaz.
onDestroy()
Sistem, hizmet artık kullanılmadığında ve kaldırılırken bu yöntemi çağırır. İş parçacıkları, kayıtlı dinleyiciler veya alıcılar gibi kaynakları temizlemek için hizmetiniz bunu uygulamalıdır. Bu, hizmetin aldığı son çağrıdır.

Bir bileşen hizmeti startService() çağrısıyla başlatırsa (bu bir onStartCommand() çağrısıyla sonuçlanır) stopSelf() ile kendiliğinden durana veya başka bir bileşen stopService() çağrısı yaparak çalışmayı durdurana kadar hizmet çalışmaya devam eder.

Bir bileşen hizmeti oluşturmak için bindService() çağrısı yaparsa ve onStartCommand() çağrılmazsa hizmet, yalnızca bileşen kendisine bağlı olduğu sürece çalışır. Sistem, tüm istemcileriyle bağlantısı kaldırıldıktan sonra hizmeti kaldırır.

Android sistemi, bir hizmeti yalnızca bellek azaldığında durdurur ve kullanıcı odaklı olan etkinlik için sistem kaynaklarını kurtarmalıdır. Hizmet, kullanıcı odağı olan bir etkinliğe bağlıysa sonlandırılma olasılığı daha düşüktür. Hizmetin ön planda çalıştığı bildirilmişse nadiren sonlandırılır. Hizmet başlatılırsa ve uzun süredir çalışıyorsa sistem, zaman içinde arka plan görevleri listesindeki konumunu düşürür ve hizmet, kullanıma sunulmaya elverişli hale gelir. Hizmetiniz başlatıldıysa sistem tarafından yapılan yeniden başlatma işlemlerini sorunsuz şekilde gerçekleştirecek şekilde tasarlamanız gerekir. Sistem, hizmetinizi sonlandırırsa kaynaklar kullanılabilir hale gelir gelmez hizmeti yeniden başlatır ancak bu, onStartCommand() ürününden döndürdüğünüz değere de bağlıdır. Sistemin bir hizmeti ne zaman kaldırabileceği hakkında daha fazla bilgi edinmek için İşlemler ve İş parçacığı oluşturma belgesine bakın.

Aşağıdaki bölümlerde startService() ve bindService() hizmet yöntemlerini nasıl oluşturacağınızı ve diğer uygulama bileşenlerinden nasıl kullanacağınızı öğreneceksiniz.

Manifest'te hizmet bildirme

Tüm hizmetleri, etkinlikler ve diğer bileşenlerde olduğu gibi, uygulamanızın manifest dosyasında da beyan etmeniz gerekir.

Hizmetinizi bildirmek için <service> öğesini <application> öğesinin alt öğesi olarak ekleyin. Örnek:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

Hizmetinizi manifest dosyasında tanımlama hakkında daha fazla bilgi edinmek için <service> öğe referansına bakın.

Hizmeti başlatmak için gereken izinler ve hizmetin çalışması gereken süreç gibi özellikleri tanımlamak amacıyla <service> öğesine ekleyebileceğiniz başka özellikler de vardır. android:name özelliği, gerekli tek özelliktir ve hizmetin sınıf adını belirtir. Uygulamanızı yayınladıktan sonra, hizmeti başlatma veya bağlamayla ilgili açık amaçlara bağımlılık nedeniyle kod kırma riskini önlemek için bu adı değiştirmeden bırakın (Değiştirilemeyen Şeyler blog yayınını okuyun).

Dikkat: Uygulamanızın güvenli olduğundan emin olmak için Service başlatırken her zaman açık intent kullanın ve hizmetleriniz için intent filtreleri beyan etmeyin. Bir hizmeti başlatmak için üstü kapalı niyet kullanmak, güvenlik açısından risk teşkil eder. Çünkü amaca yanıt veren hizmetten emin olamazsınız ve kullanıcı hangi hizmetin başladığını göremez. Android 5.0 (API düzeyi 21) sürümünden itibaren, dolaylı bir niyetle bindService() yöntemini çağırırsanız sistem bir istisna oluşturur.

android:exported özelliğini ekleyip false değerine ayarlayarak hizmetinizin yalnızca uygulamanızın kullanımına sunulduğundan emin olabilirsiniz. Bu durum, açık bir amaç kullanılırken bile diğer uygulamaların hizmetinizi başlatmasını etkili bir şekilde durdurur.

Not: Kullanıcılar, cihazlarında hangi hizmetlerin çalıştığını görebilir. Tanımadığı veya güvenmediği bir hizmet görürse bu hizmeti durdurabilir. Hizmetinizin kullanıcılar tarafından yanlışlıkla durdurulmasını önlemek için uygulama manifestinizdeki <service> öğesine android:description özelliğini eklemeniz gerekir. Açıklama bölümüne hizmetin ne yaptığını ve sağladığı faydaları açıklayan kısa bir cümle ekleyin.

Başlatılmış hizmet oluşturma

Başlatılan hizmet, başka bir bileşenin startService() yöntemini çağırarak başlattığı bir hizmettir. Bu da hizmetin onStartCommand() yöntemine çağrıyla sonuçlanır.

Bir hizmet başlatıldığında, başlatan bileşenden bağımsız bir yaşam döngüsüne sahiptir. Hizmet, hizmeti başlatan bileşen kaldırılsa bile arka planda süresiz olarak çalışabilir. Bu nedenle, işi stopSelf() çağırarak hizmetin kendisini durdurması gerekir. Alternatif olarak, başka bir bileşen stopService() işlevini çağırarak hizmeti durdurabilir.

Etkinlik gibi bir uygulama bileşeni, startService() çağrısı yaparak ve hizmeti belirten ve hizmetin kullanacağı verileri içeren bir Intent ileterek hizmeti başlatabilir. Hizmet, bu Intent değerini onStartCommand() yöntemiyle alır.

Örneğin, bir etkinliğin bazı verileri online veritabanına kaydetmesi gerektiğini varsayalım. Etkinlik, bir tamamlayıcı hizmet başlatabilir ve startService() işlevine bir amaç ileterek bu hizmete verileri kaydedecek şekilde sunabilir. Hizmet, amacı onStartCommand() içinde alır, internete bağlanır ve veritabanı işlemini gerçekleştirir. İşlem tamamlandığında hizmet kendini durdurur ve kaldırılır.

Dikkat: Bir hizmet, varsayılan olarak bildirildiği uygulamayla aynı süreçte ve uygulamanın ana iş parçacığında çalışır. Hizmetiniz, kullanıcı aynı uygulamadan bir etkinlikle etkileşimde bulunurken yoğun veya engelleme işlemleri gerçekleştirirse hizmet, etkinlik performansını yavaşlatır. Uygulama performansının etkilenmemesi için hizmet içinde yeni bir iş parçacığı başlatın.

Service sınıfı, tüm hizmetler için temel sınıftır. Bu sınıfı genişlettiğinizde, hizmetin tüm çalışmasını tamamlayabileceği yeni bir iş parçacığı oluşturmanız önemlidir. Hizmet, varsayılan olarak uygulamanızın ana iş parçacığını kullanır. Bu da uygulamanızın çalıştığı tüm etkinliklerin performansını yavaşlatabilir.

Android çerçevesi, tüm başlatma isteklerini tek tek işlemek için bir çalışan iş parçacığı kullanan Service IntentService alt sınıfını da sağlar. Arka planda yürütme sınırları kullanıma sunulması nedeniyle Android 8 Oreo'dan itibaren iyi çalışmayacağından bu sınıfın kullanılması yeni uygulamalar için önerilmez. Ayrıca, Android 11'den itibaren kullanımdan kaldırılmıştır. JobIntentService'i, Android'in yeni sürümleriyle uyumlu olan IntentService için yedek olarak kullanabilirsiniz.

Aşağıdaki bölümlerde kendi özel hizmetinizi nasıl uygulayabileceğiniz açıklanmaktadır. Ancak çoğu kullanım alanında bunun yerine WorkManager'ı kullanmanız önemle tavsiye edilir. İhtiyaçlarınıza uygun bir çözüm olup olmadığını görmek için Android'de arka planda işleme kılavuzuna bakın.

Hizmet sınıfını genişletme

Service sınıfını her gelen amacı işleyecek şekilde genişletebilirsiniz. Temel bir uygulama aşağıdaki gibi görünebilir:

Kotlin

class HelloService : Service() {

    private var serviceLooper: Looper? = null
    private var serviceHandler: ServiceHandler? = null

    // Handler that receives messages from the thread
    private inner class ServiceHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            try {
                Thread.sleep(5000)
            } catch (e: InterruptedException) {
                // Restore interrupt status.
                Thread.currentThread().interrupt()
            }

            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(msg.arg1)
        }
    }

    override fun onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
            start()

            // Get the HandlerThread's Looper and use it for our Handler
            serviceLooper = looper
            serviceHandler = ServiceHandler(looper)
        }
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show()

        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        serviceHandler?.obtainMessage()?.also { msg ->
            msg.arg1 = startId
            serviceHandler?.sendMessage(msg)
        }

        // If we get killed, after returning from here, restart
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        // We don't provide binding, so return null
        return null
    }

    override fun onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
    }
}

Java

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

Örnek kod, onStartCommand() içindeki tüm gelen aramaları işler ve çalışmayı arka plandaki bir iş parçacığında çalışan bir Handler üzerinde yayınlar. IntentService ile aynı şekilde çalışır ve tüm istekleri sırayla işler. Örneğin, aynı anda birden fazla istek çalıştırmak istiyorsanız kodu iş parçacığı havuzunda çalıştırılacak şekilde değiştirebilirsiniz.

onStartCommand() yönteminin bir tam sayı döndürmesi gerektiğini unutmayın. Tam sayı, sistemin hizmeti sonlandırması durumunda sistemin hizmeti nasıl devam ettireceğini açıklayan bir değerdir. onStartCommand() öğesinden döndürülen değer aşağıdaki sabit değerlerden biri olmalıdır:

START_NOT_STICKY
onStartCommand() işlevi döndürüldükten sonra sistem hizmeti sonlandırırsa bekleyen teslim tarihleri olmadığı sürece hizmeti yeniden oluşturmayın. Bu, gerekli olmadığı durumlarda ve uygulamanız henüz tamamlanmamış işleri yeniden başlatabildiği durumlarda hizmetinizi çalıştırmaktan kaçınmak için en güvenli seçenektir.
START_STICKY
onStartCommand() geri döndükten sonra sistem hizmeti sonlandırırsa hizmeti yeniden oluşturup onStartCommand() işlevini çağırın ancak son amacı yeniden teslim etmeyin. Bunun yerine, hizmeti başlatmak için bekleyen amaçlar yoksa sistem onStartCommand() işlevini null intent ile çağırır. Bu durumda, bu amaçlar teslim edilir. Bu, komut çalıştırmayan ancak süresiz olarak çalışan ve iş bekleyen medya oynatıcılar (veya benzer hizmetler) için uygundur.
START_REDELIVER_INTENT
onStartCommand() geri döndükten sonra sistem hizmeti sonlandırırsa hizmeti yeniden oluşturun ve hizmete teslim edilen son niyetle onStartCommand() çağırın. Beklemedeki tüm amaçlar sırayla teslim edilir. Bu, hemen devam ettirilmesi gereken bir işi aktif olarak gerçekleştiren hizmetler (ör. dosya indirme) için uygundur.

Bu dönüş değerleri hakkında daha fazla bilgi için her bir sabitle ilgili olarak bağlantılı referans belgelerine bakın.

Hizmet başlatma

Intent öğesini startService() veya startForegroundService() cihazına ileterek bir etkinlikten veya başka bir uygulama bileşeninden hizmeti başlatabilirsiniz. Android sistemi, hizmetin onStartCommand() yöntemini çağırır ve buna, hangi hizmetin başlatılacağını belirten Intent özelliğini iletir.

Not: Uygulamanız API düzeyi 26 veya üstünü hedefliyorsa sistem, arka plan hizmetlerinin kullanımı veya oluşturulması için uygulamanın kendisi ön planda olmadığı sürece kısıtlamalar uygular. Bir uygulamanın ön plan hizmeti oluşturması gerekiyorsa uygulama startForegroundService() işlevini çağırmalıdır. Bu yöntem bir arka plan hizmeti oluşturur ancak bu yöntem sisteme, hizmetin kendisini ön plana yükselteceği sinyalini verir. Hizmet oluşturulduktan sonra startForeground() yöntemini beş saniye içinde çağırmalıdır.

Örneğin bir etkinlik, aşağıda gösterildiği gibi startService() ile açık bir amaç kullanarak önceki bölümde (HelloService) örnek hizmeti başlatabilir:

Kotlin

startService(Intent(this, HelloService::class.java))

Java

startService(new Intent(this, HelloService.class));

startService() yöntemi hemen geri döner ve Android sistemi hizmetin onStartCommand() yöntemini çağırır. Hizmet zaten çalışmıyorsa sistem önce onCreate(), ardından onStartCommand() yöntemini çağırır.

Hizmet de bağlayıcı sağlamazsa startService() ile iletilen amaç, uygulama bileşeni ile hizmet arasındaki tek iletişim modudur. Ancak hizmetin bir sonucu geri göndermesini isterseniz hizmeti başlatan istemci, getBroadcast() ile bir yayın için PendingIntent oluşturup bunu hizmeti başlatan Intent içindeki hizmete sunabilir. Hizmet daha sonra bir sonuç sunmak için yayını kullanabilir.

Hizmeti başlatmak için yapılan birden fazla istek, hizmetin onStartCommand() öğesine birden çok karşılık gelen çağrıyla sonuçlanır. Ancak hizmeti durdurmak için yalnızca tek bir istekte bulunulması (stopSelf() veya stopService() ile) gerekir.

Bir hizmeti durdurma

Başlatılmış bir hizmet kendi yaşam döngüsünü yönetmelidir. Diğer bir deyişle, sistemin, sistem belleğini kurtarması gerektiği ve onStartCommand() geri dönüldükten sonra hizmet çalışmaya devam etmediği sürece hizmeti durdurmaz veya kaldırmaz. Hizmetin stopSelf() yöntemini çağırarak kendini durdurması gerekir. Aksi takdirde, başka bir bileşen stopService() işlevini çağırarak hizmeti durdurabilir.

stopSelf() veya stopService() ile durdurma istendiğinde sistem, hizmeti mümkün olan en kısa sürede kaldırır.

Hizmetiniz aynı anda onStartCommand() öğesine yönelik birden fazla isteği gerçekleştiriyorsa yeni bir başlatma isteği almış olabileceğinizden (ilk isteğin sonunda durmak, ikinci isteğin sonlandırılmasına neden olur) bir başlatma isteğini işlemeyi tamamladıktan sonra hizmeti durdurmayın. Bu sorunu önlemek amacıyla hizmeti durdurma isteğinizin her zaman en son başlatma isteğine dayalı olduğundan emin olmak için stopSelf(int) öğesini kullanabilirsiniz. Yani stopSelf(int) yöntemini çağırdığınızda durdurma isteğinizin karşılık geldiği başlatma isteğinin (onStartCommand() öğesine gönderilen startId) kimliğini iletirsiniz. Bu durumda, stopSelf(int) çağrılmadan önce hizmet yeni bir başlatma isteği alırsa kimlik eşleşmez ve hizmet durmaz.

Dikkat: Sistem kaynaklarının boşa harcanmasını ve pil gücünün harcanmasını önlemek için uygulamanızın çalışması bittiğinde hizmetlerini durdurduğundan emin olun. Gerekirse diğer bileşenler stopService() işlevini çağırarak hizmeti durdurabilir. Hizmet için bağlamayı etkinleştirseniz bile, onStartCommand() araması alması durumunda hizmeti her zaman kendiniz durdurmanız gerekir.

Bir hizmetin yaşam döngüsü hakkında daha fazla bilgi edinmek için aşağıdaki Hizmet Yaşam Döngüsünü Yönetme bölümüne bakın.

Bağlı hizmet oluşturma

Bağlı hizmet, uzun süreli bir bağlantı oluşturmak için bindService() yöntemini çağırarak uygulama bileşenlerinin ona bağlanmasına olanak tanır. Genellikle bileşenlerin startService() yöntemini çağırarak başlatmasına izin vermez.

Uygulamanızdaki etkinlikler ve diğer bileşenlerden hizmetle etkileşimde bulunmak veya uygulamanızın işlevlerinden bazılarını işlemler arası iletişim (IPC) üzerinden diğer uygulamalara sunmak istediğinizde bağlı bir hizmet oluşturun.

Bağlı bir hizmet oluşturmak amacıyla hizmetle iletişimde kullanılacak arayüzü tanımlayan bir IBinder döndürmek için onBind() geri çağırma yöntemini uygulayın. Daha sonra diğer uygulama bileşenleri, arayüzü almak ve hizmette yöntemleri çağırmaya başlamak için bindService() işlevini çağırabilir. Hizmet yalnızca kendisine bağlı uygulama bileşenini sunmak için çalışır. Bu nedenle, hizmete bağlı bir bileşen olmadığında sistem onu kaldırır. Bağlı bir hizmeti, onStartCommand() aracılığıyla başlatıldığında geçerli olan şekilde durdurmanız gerekmez.

Bağlı hizmet oluşturmak için bir istemcinin hizmetle nasıl iletişim kurabileceğini belirten arayüzü tanımlamanız gerekir. Hizmet ile istemci arasındaki bu arayüz, IBinder uygulaması olmalıdır ve hizmetiniz, onBind() geri çağırma yönteminden döndürmelidir. İstemci IBinder bilgisini aldıktan sonra bu arayüz üzerinden hizmetle etkileşimde bulunmaya başlayabilir.

Birden çok istemci hizmete aynı anda bağlanabilir. Bir istemci hizmetle etkileşimi tamamladığında, bağlantıyı kaldırmak için unbindService() işlevini çağırır. Hizmete bağlı hiçbir istemci olmadığında sistem hizmeti kaldırır.

Bağlı bir hizmeti uygulamanın birden fazla yolu vardır ve uygulama, başlatılan bir hizmetten daha karmaşıktır. Bu nedenlerle, bağlı hizmet açıklaması Sınır Hizmetler ile ilgili ayrı bir belgede görünür.

Kullanıcıya bildirim gönderir

Bir hizmet çalışırken, atıştırma çubuğu bildirimlerini veya durum çubuğu bildirimlerini kullanarak kullanıcıya etkinlikleri bildirebilir.

Atıştırmalık çubuğu bildirimi, geçerli pencerenin yüzeyinde, kaybolmadan önce sadece bir an için görünen mesajdır. Durum çubuğu bildiriminin durum çubuğunda, kullanıcının işlem yapmak (örneğin, etkinlik başlatmak) için seçebileceği bir mesaj içeren simge sağlanır.

Genelde durum çubuğu bildirimi, dosya indirme gibi bir arka plan çalışması tamamlandığında kullanılacak en iyi tekniktir ve kullanıcı artık bu bildirim üzerinde işlem yapabilir. Kullanıcı, genişletilmiş görünümden bildirimi seçtiğinde, bildirim bir etkinlik başlatabilir (indirilen dosyayı görüntülemek gibi).

Bir hizmetin yaşam döngüsünü yönetme

Bir hizmetin yaşam döngüsü, bir etkinliğin yaşam döngüsünden çok daha basittir. Ancak, bir hizmet kullanıcının farkında olmadan arka planda çalışabileceğinden hizmetin nasıl oluşturulduğuna ve yok edildiğine dikkat etmeniz daha da önemlidir.

Hizmet yaşam döngüsü, oluşturulduğu andan silindiği ana kadar aşağıdaki iki yoldan birini izleyebilir:

  • Başlatılmış bir hizmet

    Hizmet, başka bir bileşen startService() çağırdığında oluşturulur. Bu durumda hizmet süresiz olarak çalışır ve stopSelf() yöntemini çağırarak kendini durdurması gerekir. Başka bir bileşen de stopService() yöntemini çağırarak hizmeti durdurabilir. Hizmet durdurulduğunda sistem hizmeti kaldırır.

  • Bağlı bir hizmet

    Hizmet, başka bir bileşen (bir istemci) bindService() çağırdığında oluşturulur. Daha sonra istemci, bir IBinder arayüzü üzerinden hizmetle iletişim kurar. İstemci, unbindService() çağrısı yaparak bağlantıyı kapatabilir. Birden çok istemci aynı hizmete bağlanabilir. Bu istemcilerin tümü bağlandığında sistem hizmeti kaldırır. Hizmetin kendini durdurması gerekmez.

Bu iki yol birbirinden tamamen ayrı değildir. startService() ile başlatılmış bir hizmeti bağlayabilirsiniz. Örneğin, çalınacak müziği tanımlayan bir Intent ile startService() işlevini çağırarak bir arka plan müziği hizmetini başlatabilirsiniz. Daha sonra, kullanıcı oynatıcı üzerinde biraz kontrol sahibi olmak veya mevcut şarkı hakkında bilgi almak istediğinde, bir etkinlik bindService() çağrısı yaparak hizmete bağlanabilir. Bu gibi durumlarda, tüm istemcilerin bağlantısı kaldırılana kadar stopService() veya stopSelf() hizmeti gerçekten durdurmaz.

Yaşam döngüsü geri çağırmalarını uygulama

Tıpkı bir etkinlik gibi hizmetler de hizmetin durumundaki değişiklikleri izlemek ve uygun zamanlarda çalışma gerçekleştirmek için uygulayabileceğiniz yaşam döngüsü geri çağırma yöntemlerine sahiptir. Aşağıdaki iskelet hizmet, yaşam döngüsü yöntemlerinin her birini göstermektedir:

Kotlin

class ExampleService : Service() {
    private var startMode: Int = 0             // indicates how to behave if the service is killed
    private var binder: IBinder? = null        // interface for clients that bind
    private var allowRebind: Boolean = false   // indicates whether onRebind should be used

    override fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Java

public class ExampleService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Not: Etkinlik yaşam döngüsü geri çağırma yöntemlerinin aksine, bu geri çağırma yöntemlerinin üst sınıf uygulamasını çağırmanız gerekmez.

2. Şekil. Hizmet yaşam döngüsü. Soldaki şema, hizmetin startService() ile oluşturulduğu andaki yaşam döngüsünü, sağdaki şema ise hizmetin bindService() ile oluşturulduğu andaki yaşam döngüsünü göstermektedir.

Şekil 2'de bir hizmetin tipik geri çağırma yöntemleri gösterilmektedir. Bu şekil, startService() tarafından oluşturulan hizmetleri bindService() tarafından oluşturulan hizmetlerden ayırsa da herhangi bir hizmetin, nasıl başlatılmış olursa olsun, müşterilerin bu hizmete bağlanmasına olanak tanıyabileceğini unutmayın. Başlangıçta onStartCommand() ile başlatılan bir hizmet (startService() numaralı telefonu arayan bir istemci tarafından) yine de onBind() numaralı telefona yapılan bir arama alabilir (bir istemci bindService() araması yaptığında).

Bu yöntemleri uygulayarak hizmetin yaşam döngüsündeki iç içe yerleştirilmiş şu iki döngüyü izleyebilirsiniz:

  • Bir hizmetin kullanım ömrünün tamamı, onCreate() işlevinin çağrıldığı zaman ile onDestroy() ürününün geri döndüğü zaman arasında gerçekleşir. Tıpkı etkinlikler gibi, hizmet de ilk kurulumunu onCreate() ürününde yapar ve kalan tüm kaynakları onDestroy() ürününde serbest bırakır. Örneğin, bir müzik çalma hizmeti, müziğin onCreate() üzerinde çalındığı ileti dizisini oluşturup ardından onDestroy() üzerinde bu ileti dizisini durdurabilir.

    Not: onCreate() ve onDestroy() yöntemleri, startService() veya bindService() tarafından oluşturulmuş olmaları fark etmeksizin tüm hizmetler için çağrılır.

  • Bir hizmetin etkin ömrü, onStartCommand() veya onBind() çağrısıyla başlar. Her yönteme, startService() veya bindService() yöntemine geçirilen Intent verilir.

    Hizmet başlatıldıysa etkin kullanım ömrü, tüm kullanım ömrü sona erdiği anda sona erer (hizmet, onStartCommand() iade edildikten sonra bile etkin olmaya devam eder). Hizmet bağlıysa onUnbind() döndüğünde etkin kullanım ömrü sona erer.

Not: Başlatılan bir hizmet stopSelf() veya stopService() çağrısıyla durdurulur, ancak ilgili hizmet için geri arama yoktur (onStop() geri çağırma yoktur). Hizmet bir istemciye bağlı değilse sistem, hizmet durdurulduğunda hizmeti kaldırır. Alınan tek geri çağırma onDestroy()'tir.

Bağlama sağlayan bir hizmet oluşturma hakkında daha fazla bilgi edinmek için Sınır Hizmetleri belgesine bakın. Bu belgede, Bağlı bir hizmetin yaşam döngüsünü yönetme bölümündeki onRebind() geri çağırma yöntemi hakkında daha fazla bilgi bulabilirsiniz.