Hizmetlere genel bakış

Service, arka planda uzun süren işlemler gerçekleştirebilen bir uygulama bileşenidir. 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 çalışmaya devam edebilir. Ayrıca bir bileşen, bir hizmete bağlanarak onunla etkileşim kurabilir ve hatta işlemler arası iletişim (IPC) gerçekleştirebilir. Örneğin, bir hizmet arka planda ağ işlemlerini gerçekleştirebilir, müzik çalabilir, dosya G/Ç işlemi yapabilir veya bir içerik sağlayıcıyla etkileşime geçebilir.

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

Hizmet Türleri

Üç farklı hizmet türü vardır:

Ön plan

Ön plan hizmetleri, kullanıcının fark edebileceği bazı işlemleri gerçekleştirir. Örneğin, bir ses uygulaması ses parçası çalmak için ön plan hizmetini kullanır. Ön plan hizmetleri bir bildirim göstermelidir. Ön plan hizmetleri, kullanıcı uygulamayla etkileşimde olmasa bile çalışmaya devam eder.

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

Uygulamanızda ön plan hizmetlerini yapılandırma hakkında daha fazla bilgi edinin.

Not: WorkManager API, görevleri planlamanın esnek bir yolunu sunar ve gerekirse bu işleri ön plan hizmetleri olarak çalıştırabilir. Birçok durumda, doğrudan ön plan hizmetlerini kullanmak yerine WorkManager'ı kullanmak tercih edilir.

Arka plan
Arka plan hizmetleri, kullanıcı tarafından doğrudan fark edilmeyen bir işlem gerçekleştirir. Örneğin, bir uygulama depolama alanını sıkıştırmak için bir hizmet kullanıyorsa bu genellikle arka plan hizmetidir.

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

Bağlı
Bir uygulama bileşeni bindService()'ı çağırarak bir hizmete bağlandığında hizmet bağlanır. Bağlı hizmet, bileşenlerin hizmetle etkileşime geçmesine, istek göndermesine, sonuç almasına ve hatta işlemler arası iletişim (IPC) ile işlemler arasında bunu yapmasına olanak tanıyan bir istemci-sunucu arayüzü sunar. Bağlı hizmetler yalnızca başka bir uygulama bileşenine bağlı oldukları sürece çalışır. Birden fazla bileşen aynı anda hizmete bağlanabilir ancak bunların tümü bağlantısını kaldırdığında hizmet yok edilir.

Bu dokümanda genellikle başlatılan ve bağlanan hizmetler ayrı ayrı ele alınsa da hizmetiniz her iki şekilde de çalışabilir. Hizmetiniz başlatılabilir (sınırsız olarak çalışacak şekilde) ve bağlanmaya da izin verebilir. Bunun için birkaç geri çağırma yöntemi uygulamanız yeterlidir: 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 olup olmadığına bakılmaksızın, herhangi bir uygulama bileşeni, bir bileşenin bir etkinliği kullanabileceği şekilde (ayrı bir uygulamadan bile) hizmeti Intent ile başlatarak kullanabilir. Ancak manifest dosyasında hizmeti gizli olarak tanımlayabilir ve diğer uygulamalardan erişimi engelleyebilirsiniz. Bu konu, Manifestte hizmeti tanımlama bölümünde daha ayrıntılı olarak ele alınmıştır.

Hizmet ile ileti dizisi arasında seçim yapma

Hizmet, kullanıcı uygulamanızla etkileşimde bulunmadığında bile arka planda çalışabilen bir bileşendir. Dolayısıyla, yalnızca ihtiyacınız olduğunda hizmet oluşturmalısınız.

Ana mesaj dizinizin dışında ancak yalnızca kullanıcı uygulamanızla etkileşimde bulunurken işlem yapmanız gerekiyorsa bunun yerine başka bir uygulama bileşeni bağlamında yeni bir mesaj dizisi oluşturmanız gerekir. Örneğin, yalnızca etkinliğiniz çalışırken müzik çalmak istiyorsanız onCreate()'te bir mesaj dizisi oluşturabilir, onStart()'te çalıştırmaya başlayabilir ve onStop()'de durdurabilirsiniz. Ayrıca geleneksel Thread sınıfı yerine java.util.concurrent paketindeki iş parçacığı havuzlarını ve yürütücüleri ya da Kotlin iş parçacıklarını kullanabilirsiniz. Yürütmeyi arka plan iş parçalarına taşıma hakkında daha fazla bilgi için Android'de iş parçacıkları belgesine bakın.

Kullandığınız hizmetler varsayılan olarak uygulamanızın ana iş parçacığında çalışmaya devam eder. Bu nedenle, yoğun veya engelleyen işlemler gerçekleştiriyorsa 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 önemli yönlerini yöneten bazı geri çağırma yöntemlerini geçersiz kılmanız ve uygun durumlarda bileşenlerin hizmete bağlanmasına olanak tanıyan bir mekanizma sağlamanız gerekir. Geçersiz kılmanız gereken en önemli geri çağırma yöntemleri şunlardır:

onStartCommand()
Sistem, başka bir bileşen (ör. etkinlik) hizmetin başlatılmasını istediğinde startService()'yi çağırarak bu yöntemi tetikler. Bu yöntem çalıştırıldığında hizmet başlatılır ve arka planda süresiz olarak çalışabilir. Bu yöntemi uygularsanız stopSelf() veya stopService() numaralı telefonu arayarak işin tamamlanmasının ardından hizmeti durdurmak sizin sorumluluğunuzdadır. Yalnızca bağlama sağlamak istiyorsanız bu yöntemi uygulamanız gerekmez.
onBind()
Sistem, başka bir bileşen hizmete bağlanmak istediğinde (ör. RPC gerçekleştirmek için) bindService()'yi çağırarak bu yöntemi çağırır. Bu yöntemi uygularken, istemcilerin IBinder döndürerek hizmetle iletişim kurmak için kullanacağı bir arayüz sağlamanız gerekir. Bu yöntemi her zaman uygulamanız gerekir. Ancak bağlamaya izin vermek istemiyorsanız null döndürmeniz gerekir.
onCreate()
Sistem, hizmet ilk oluşturulduğunda (onStartCommand() veya onBind() çağrılmadan önce) tek seferlik kurulum işlemlerini gerçekleştirmek için bu yöntemi çağırır. Hizmet zaten çalışıyorsa bu yöntem çağrılmaz.
onDestroy()
Sistem, hizmet artık kullanılmadığında ve yok edildiğinde bu yöntemi çağırır. Hizmetiniz, mesaj dizileri, kayıtlı dinleyiciler veya alıcı gibi kaynakları temizlemek için bunu uygulamalıdır. Bu, hizmetin aldığı son aramadır.

Bir bileşen, startService()'ü çağırarak hizmeti başlatırsa (bu, onStartCommand() çağrısıyla sonuçlanır) hizmet, stopSelf() ile kendini durdurana veya başka bir bileşen stopService()'ı çağırarak durdurana kadar çalışmaya devam eder.

Bir bileşen, hizmeti oluşturmak için bindService()'ü çağırır ve onStartCommand() çağrılmazsa hizmet yalnızca bileşene bağlı olduğu sürece çalışır. Hizmet, tüm istemcilerinden ayrıldıktan sonra sistem tarafından yok edilir.

Android sistemi, yalnızca bellek düşük olduğunda ve kullanıcının odak noktası olan etkinlik için sistem kaynaklarını kurtarması gerektiğinde bir hizmeti durdurur. Hizmet, kullanıcı odaklı bir etkinliğe bağlıysa sonlandırılma olasılığı daha düşüktür. Hizmetin ön planda çalışacağı belirtilmişse nadiren sonlandırılır. Hizmet başlatıldıysa ve uzun süre çalışıyorsa sistem, zaman içinde arka plan görevleri listesinde yerini düşürür ve hizmetin sonlandırılma olasılığı artar. Hizmetiniz başlatıldıysa sistemi tarafından yeniden başlatma işlemlerini sorunsuz şekilde ele alacak şekilde tasarlamanız gerekir. Sistem, hizmetinizi sonlandırır ve kaynaklar kullanılabilir hale gelir gelmez yeniden başlatır. Ancak bu durum, onStartCommand() işlevinden döndürdüğünüz değere de bağlıdır. Sistemin bir hizmeti ne zaman yok edebileceği hakkında daha fazla bilgi için İşlemler ve İş Parçaları belgesine bakın.

Aşağıdaki bölümlerde, startService() ve bindService() hizmet yöntemlerini nasıl oluşturabileceğinizi ve bunları diğer uygulama bileşenlerinden nasıl kullanabileceğinizi göreceksiniz.

Manifest'te hizmet tanımlama

Tüm hizmetleri, etkinlikler ve diğer bileşenler için yaptığınız gibi uygulamanızın manifest dosyasında bildirmeniz gerekir.

Hizmetinizi beyan etmek için <application> öğesinin alt öğesi olarak bir <service> öğesi ekleyin. Örnek:

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

Hizmetinizi manifest dosyasında beyan etme hakkında daha fazla bilgi için <service> öğesi referansına bakın.

Hizmeti başlatmak için gereken izinler ve hizmetin çalışması gereken işlem gibi özellikleri tanımlamak üzere <service> öğesine ekleyebileceğiniz başka özellikler de vardır. android:name özelliği, hizmetin sınıf adını belirten tek zorunlu özelliktir. Uygulamanızı yayınladıktan sonra, hizmeti başlatmak veya bağlamak için açık intentlere bağlılık nedeniyle kodun bozulma riskini önlemek için bu adı değiştirmeyin (Değiştirilemeyen Şeyler blog yayınını okuyun).

Dikkat: Uygulamanızın güvenliğini sağlamak için Service başlatırken her zaman açık bir intent kullanın ve hizmetleriniz için intent filtreleri tanımlamayın. Bir hizmeti başlatmak için dolaylı intent kullanmak güvenlik açısından risklidir. Bunun nedeni, intent'e yanıt veren hizmetten emin olamama ve kullanıcının hangi hizmetin başlatıldığını görememesinden kaynaklanır. Android 5.0 (API düzeyi 21) sürümünden itibaren, bindService() işlevini dolaylı bir intent ile çağırırsanız sistem bir istisna atar.

android:exported özelliğini ekleyerek ve false olarak ayarlayarak hizmetinizin yalnızca uygulamanızda kullanılabildiğinden emin olabilirsiniz. Bu, açık bir intent kullanıldığında bile diğer uygulamaların hizmetinizi başlatmasını etkili bir şekilde engeller.

Not: Kullanıcılar, cihazlarında hangi hizmetlerin çalıştığını görebilir. Tanımadıkları veya güvenmedikleri bir hizmet görürse hizmeti durdurabilirler. 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ünde, hizmetin ne işe yaradığını ve ne gibi avantajlar sağladığını açıklayan kısa bir cümle yazın.

Başlatılmış bir hizmet oluşturma

Başlatılan hizmet, başka bir bileşenin startService()'ü çağırarak başlattığı ve hizmetin onStartCommand() yönteminin çağrılmasına neden olan hizmettir.

Bir hizmet başlatıldığında, onu başlatan bileşenden bağımsız bir yaşam döngüsü olur. Hizmeti başlatan bileşen yok edilse bile hizmet, arka planda süresiz olarak çalışabilir. Bu nedenle, hizmet işini tamamladığında stopSelf() çağrısı yaparak kendini durdurmalıdır veya başka bir bileşen stopService() çağrısı yaparak hizmeti durdurabilir.

Etkinlik gibi bir uygulama bileşeni, startService()'ü çağırarak ve hizmeti belirten ve hizmetin kullanacağı tüm verileri içeren bir Intent göndererek hizmeti başlatabilir. Hizmet, bu Intent değerini onStartCommand() yönteminde alır.

Örneğin, bir etkinliğin bazı verileri online bir veritabanına kaydetmesi gerektiğini varsayalım. Etkinlik, startService()'ye bir intent göndererek bir tamamlayıcı hizmet başlatabilir ve kaydedilecek verileri bu hizmete iletebilir. Hizmet, onStartCommand() içinde intent'i 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, tanımlandığı uygulamayla aynı işlemde ve varsayılan olarak bu uygulamanın ana iş akışında çalışır. Kullanıcı aynı uygulamadaki bir etkinlikle etkileşimde bulunurken hizmetiniz yoğun veya engelleme işlemleri gerçekleştiriyorsa etkinlik performansı yavaşlar. Uygulama performansını etkilememek için hizmet içinde yeni bir mesaj dizisi başlatın.

Service sınıfı, tüm hizmetler için temel sınıftır. Bu sınıfı genişletirken, hizmetin tüm çalışmaları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ırmakta olduğu tüm etkinliklerin performansını yavaşlatabilir.

Android çerçevesi, tüm başlatma isteklerini tek tek işlemek için bir işleyici iş parçacığı kullanan Service sınıfının IntentServicealt sınıfını da sağlar. Arka planda yürütme sınırlarının kullanıma sunulması nedeniyle Android 8 Oreo'dan itibaren iyi çalışmayacaktır. Bu nedenle, yeni uygulamalarda bu sınıfın kullanılması önerilmez. Ayrıca, Android 11'den itibaren desteği sonlandırılmıştır. Android'in daha yeni sürümleriyle uyumlu IntentService yerine JobIntentService'i kullanabilirsiniz.

Aşağıdaki bölümlerde, kendi özel hizmetinizi nasıl uygulayabileceğiniz açıklanmaktadır. Bununla birlikte, çoğu kullanım alanında bunun yerine WorkManager'ı kullanmayı kesinlikle düşünmeniz önerilir. İhtiyaçlarınıza uygun bir çözüm olup olmadığını görmek için Android'de arka planda işleme kılavuzuna göz atın.

Service sınıfını genişletme

Gelen her niyeti işlemek için Service sınıfını 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()'te gelen tüm aramaları işler ve işi arka plan iş parçacığında çalışan bir Handler'a gönderir. IntentService gibi çalışır ve tüm istekleri seri olarak birbiri ardına işler. Örneğin, birden fazla isteği aynı anda çalıştırmak istiyorsanız kodu, işi bir iş parçacığı havuzunda çalıştıracak şekilde değiştirebilirsiniz.

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

START_NOT_STICKY
Sistem, onStartCommand() döndükten sonra hizmeti sonlandırırsa yayınlanacak bekleyen intent'ler olmadığı sürece hizmeti yeniden oluşturmayın. Bu seçenek, gerekli olmadığında hizmetinizin çalışmasını önlemek ve uygulamanızın tamamlanmamış işleri yeniden başlatabilmesi için en güvenli seçenektir.
START_STICKY
Sistem, onStartCommand() döndükten sonra hizmeti sonlandırırsa hizmeti yeniden oluşturun ve onStartCommand() işlevini çağırın ancak son amacı yeniden yayınlamayın. Bunun yerine sistem, hizmeti başlatmak için bekleyen intent'ler olmadığı sürece onStartCommand()'ü null intent ile çağırır. Bu durumda, bu intent'ler yayınlanır. Bu, komutları yürütmeyen ancak süresiz olarak çalışan ve iş bekleyen medya oynatıcıları (veya benzer hizmetler) için uygundur.
START_REDELIVER_INTENT
Sistem, onStartCommand() döndükten sonra hizmeti sonlandırırsa hizmeti yeniden oluşturun ve hizmete iletilen son intent ile onStartCommand()'yi çağırın. Bekleyen tüm intent'ler sırayla yayınlanır. Bu, dosya indirme gibi hemen devam ettirilmesi gereken bir işi etkin olarak gerçekleştiren hizmetler için uygundur.

Bu döndürülen değerler hakkında daha fazla bilgi için her bir sabitin bağlı referans dokümanlarına bakın.

Hizmeti başlatma

Bir hizmeti, startService() veya startForegroundService()'ye Intent göndererek bir etkinlikten ya da başka bir uygulama bileşeninden başlatabilirsiniz. Android sistemi, hizmetin onStartCommand() yöntemini çağırır ve hangi hizmetin başlatılacağını belirten Intent parametresini iletir.

Not: Uygulamanız API düzeyi 26 veya sonraki sürümleri hedefliyorsa sistem, uygulamanın kendisi ön planda olmadığı sürece arka plan hizmetlerini kullanma veya oluşturma konusunda kısıtlamalar uygular. Bir uygulamanın ön plan hizmeti oluşturması gerekiyorsa startForegroundService() çağrısı yapmalıdır. Bu yöntem bir arka plan hizmeti oluşturur ancak yöntem, hizmetin kendisini ön plana çıkaracağını sisteme bildirir. Hizmet oluşturulduktan sonra beş saniye içinde startForeground() yöntemini çağırmalıdır.

Örneğin, bir etkinlik, burada gösterildiği gibi startService() içeren açık bir intent kullanarak önceki bölümdeki örnek hizmeti (HelloService) başlatabilir:

Kotlin

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

Java

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

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

Hizmet, bağlama da sahip değilse uygulama bileşeni ile hizmet arasındaki tek iletişim şekli, startService() ile gönderilen intent'tir. Ancak hizmetin bir sonuç göndermesini istiyorsanız hizmeti başlatan istemci, yayın için bir PendingIntent (getBroadcast() ile) oluşturabilir ve hizmeti başlatan Intent içinde hizmete iletebilir. Hizmet daha sonra bir sonuç sunmak için yayını kullanabilir.

Hizmeti başlatma isteği birden fazla kez gönderilirse hizmetin onStartCommand() işlevine birden fazla kez çağrı gönderilir. Ancak hizmeti durdurmak için yalnızca bir hizmet durdurma isteği (stopSelf() veya stopService() ile) gönderilmesi gerekir.

Bir hizmeti durdurma

Başlatılan bir hizmet kendi yaşam döngüsünü yönetmelidir. Yani sistem, sistem belleğini kurtarması gerekmediği sürece hizmeti durdurmaz veya yok etmez ve hizmet, onStartCommand() döndükten sonra çalışmaya devam eder. Hizmet, stopSelf() çağrısı yaparak kendini durdurmalıdır veya başka bir bileşen stopService() çağrısı yaparak hizmeti durdurabilir.

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

Hizmetiniz onStartCommand() için birden fazla isteği eşzamanlı olarak işliyorsa yeni bir başlatma isteği almış olabileceğiniz için bir başlatma isteğini işlemeyi tamamladığınızda hizmeti durdurmamanız gerekir (ilk isteğin sonunda durdurma işlemi ikinci isteği sonlandırır). Bu sorunu önlemek için, hizmeti durdurma isteğinizin her zaman en son başlatma isteğine dayalı olmasını sağlamak üzere stopSelf(int) kullanabilirsiniz. Yani stopSelf(int)'ü çağırdığınızda, durdurma isteğinizin karşılık geldiği başlatma isteğinin kimliğini (onStartCommand()'ye gönderilen startId) iletirsiniz. Ardından, stopSelf(int) işlevini çağırmadan önce hizmet yeni bir başlatma isteği alırsa kimlik eşleşmez ve hizmet durmaz.

Dikkat: Sistem kaynaklarını ve pil gücünü boşa harcamamak için uygulamanızın, çalışmayı tamamladığında hizmetlerini durdurduğundan emin olun. Gerekirse diğer bileşenler stopService() çağrısı yaparak hizmeti durdurabilir. Hizmet için bağlamayı etkinleştirseniz bile onStartCommand() adresine çağrı gelirse hizmeti her zaman kendiniz durdurmanız gerekir.

Bir hizmetin yaşam döngüsü hakkında daha fazla bilgi için aşağıdaki Hizmetin 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() çağrısı yaparak uygulama bileşenlerinin kendisine bağlanmasına izin veren bir hizmettir. Genellikle bileşenlerin startService()'yi çağırarak başlatmasına izin vermez.

Uygulamanızdaki etkinliklerden ve diğer bileşenlerden hizmetle etkileşimde bulunmak veya uygulamanızın işlevlerinin bir kısmını işlemler arası iletişim (IPC) aracılığıyla diğer uygulamalara göstermek istediğinizde bağlı hizmet oluşturun.

Bağlı bir hizmet oluşturmak için hizmetle iletişim arayüzünü tanımlayan bir IBinder döndürmek üzere onBind() geri çağırma yöntemini uygulayın. Diğer uygulama bileşenleri, arayüzü almak ve hizmette yöntemleri çağırmaya başlamak için bindService()'ü çağırabilir. Hizmet yalnızca kendisine bağlı olan uygulama bileşenini sunmak için var olur. Bu nedenle, hizmete bağlı bileşen olmadığında sistem hizmeti siler. Bağlı bir hizmeti onStartCommand() üzerinden başlattığınızda olduğu gibi durdurmanız gerekmez.

Bağlı bir hizmet oluşturmak için istemcinin hizmetle nasıl iletişim kurabileceğini belirten arayüzü tanımlamanız gerekir. Hizmet ile istemci arasındaki bu arayüz, IBinder'ün bir uygulaması olmalıdır ve hizmetinizin onBind() geri çağırma yönteminden döndürmesi gereken şeydir. İstemci, IBinder'yi aldıktan sonra bu arayüz üzerinden hizmetle etkileşime geçebilir.

Birden fazla istemci aynı anda hizmete bağlanabilir. Bir istemci hizmetle etkileşimini tamamladığında, bağlamayı kaldırmak için unbindService() işlevini çağırır. Hizmete bağlı istemci olmadığında sistem hizmeti siler.

Bağlı bir hizmeti uygulamanın birden fazla yolu vardır ve uygulama, başlatılmış bir hizmetten daha karmaşıktır. Bu nedenlerle, bağlı hizmetlerle ilgili tartışma Bağlı Hizmetler hakkındaki ayrı bir belgede yer alır.

Kullanıcıya bildirim gönderme

Çalışan bir hizmet, snackbar bildirimleri veya durum çubuğu bildirimleri kullanarak kullanıcıyı etkinliklerden haberdar edebilir.

Snackbar bildirimi, mevcut pencerenin yüzeyinde yalnızca bir an görünen ve sonra kaybolan bir mesajdır. Durum çubuğu bildirimi, durum çubuğunda bir mesaj içeren bir simge sağlar. Kullanıcı, işlem yapmak (ör. etkinlik başlatmak) için bu simgeyi seçebilir.

Dosya indirme gibi arka planda çalışan bir işlem tamamlandığında ve kullanıcı artık işlem yapabilecek durumda olduğunda genellikle durum çubuğu bildirimi kullanmak en iyi tekniktir. Kullanıcı genişletilmiş görünümden bildirimi seçtiğinde bildirim bir etkinlik başlatabilir (ör. indirilen dosyayı görüntüleme).

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, hizmetinizin nasıl oluşturulduğuna ve kaldırıldığına daha da dikkat etmeniz gerekir.

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

  • Başlatılan bir hizmet

    Hizmet, başka bir bileşen startService()'ü çağrdığında oluşturulur. Ardından hizmet süresiz olarak çalışır ve stopSelf() çağrısı yaparak kendini durdurmalıdır. Başka bir bileşen de stopService() çağrısı yaparak hizmeti durdurabilir. Hizmet durdurulduğunda sistem tarafından silinir.

  • Bağlı hizmet

    Hizmet, başka bir bileşen (istemci) bindService()'ü çağrdığında oluşturulur. Ardından istemci, IBinder arayüzü aracılığıyla hizmetle iletişim kurar. İstemci, unbindService() çağrısı yaparak bağlantıyı kapatabilir. Birden fazla istemci aynı hizmete bağlanabilir ve bunların tümü bağlantıyı kaldırdığında sistem hizmeti siler. Hizmetin kendisini durdurması gerekmez.

Bu iki yol tamamen ayrı değildir. startService() ile başlatılmış bir hizmete bağlanabilirsiniz. Örneğin, çalacağı müziği tanımlayan bir Intent ile startService()'ü arayarak arka plan müzik hizmetini başlatabilirsiniz. Daha sonra, kullanıcı oynatıcı üzerinde biraz kontrol sahibi olmak veya mevcut şarkı hakkında bilgi edinmek istediğinde bir etkinlik bindService() çağrısı yaparak hizmete bağlanabilir. Bu gibi durumlarda, tüm istemciler bağlantısını kesene kadar stopService() veya stopSelf() hizmeti durdurmaz.

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

Bir etkinlik gibi, hizmetin de hizmetin durumundaki değişiklikleri izlemek ve uygun zamanlarda işlem yapmak için uygulayabileceğiniz yaşam döngüsü geri çağırma yöntemleri vardır. Aşağıdaki iskelet hizmette yaşam döngüsü yöntemlerinin her biri gösterilmektedir:

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.

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

Şekil 2'de, bir hizmet için tipik geri çağırma yöntemleri gösterilmektedir. Şekilde, startService() tarafından oluşturulan hizmetler bindService() tarafından oluşturulan hizmetlerden ayrılmış olsa da nasıl başlatıldığına bakılmaksızın her hizmetin, istemcilerin kendisine bağlanmasına izin verebileceğini unutmayın. Başlangıçta onStartCommand() ile başlatılan bir hizmet (startService() numaralı bir müşteri tarafından), onBind() numaralı bir müşterinin araması durumunda (bindService()) onBind() numaralı telefon için arama almaya devam edebilir.

Bu yöntemleri uygulayarak hizmetin yaşam döngüsünün aşağıdaki iki iç içe yerleştirilmiş döngüsünü izleyebilirsiniz:

  • Bir hizmetin tüm yaşam döngüsü, onCreate() çağrıldığı andan onDestroy() döndürüldüğü ana kadar gerçekleşir. Bir hizmet de etkinlik gibi ilk kurulumunu onCreate()'te yapar ve kalan tüm kaynakları onDestroy()'te serbest bırakır. Örneğin, bir müzik çalma hizmeti, müziğin onCreate()'te çalındığı ileti dizisini oluşturabilir ve ardından ileti dizisini onDestroy()'te durdurabilir.

    Not: onCreate() ve onDestroy() yöntemleri, startService() veya bindService() tarafından oluşturulmuş 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()'ye iletilen Intent verilir.

    Hizmet başlatılırsa etkin kullanım ömrü, tüm kullanım ömrünün sona ermesiyle aynı anda sona erer (onStartCommand() döndükten sonra bile hizmet etkin kalır). Hizmet bağlıysa etkin kullanım süresi, onUnbind() döndürüldüğünde sona erer.

Not: Başlatılan bir hizmet, stopSelf() veya stopService() çağrısıyla durdurulsa da hizmet için ilgili bir geri çağırma yoktur (onStop() geri çağırma yoktur). Hizmet bir istemciye bağlı değilse sistem, hizmet durdurulduğunda hizmeti yok eder. Alınan tek geri çağırma onDestroy() olur.

Bağlama sağlayan bir hizmet oluşturma hakkında daha fazla bilgi için Bağlı Hizmetler belgesine bakın. Bu belgede, Bağlı bir hizmetin yaşam döngüsünü yönetme ile ilgili bölümde onRebind() geri çağırma yöntemi hakkında daha fazla bilgi verilmektedir.