Hizmetlere genel bakış

Service, arka planda uzun süreli işlemler yapabilen bir uygulama bileşenidir. Kullanıcı arayüzü sunmaz. 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. Ayrıca, 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 işleyebilir, müzik çalabilir, dosya G/Ç'si 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 siz aksini belirtmedikçe ayrı bir süreçte çalışmaz. Uygulama Yanıt Vermiyor (ANR) hatalarından kaçınmak için tüm engelleme işlemlerini hizmet içindeki ayrı bir iş parçacığında çalıştırmanız gerekir.

Hizmet Türleri

Bunlar üç farklı hizmet türüdür:

Ön plan

Bir ön plan hizmeti, kullanıcının fark edebileceği bazı işlemler gerçekleştirir. Örneğin, bir ses uygulaması, ses parçası çalmak için bir ön plan hizmeti kullanır. Ön plan hizmetleri bir Bildirim görüntülemelidir. Ön plan hizmetleri, kullanıcı uygulamayla etkileşimde olmasa 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 planlamak için esnek bir yol sunar ve gerektiğinde bu işleri ön plan hizmetleri olarak çalıştırabilir. Çoğu durumda, doğrudan ön plan hizmetlerini kullanmak yerine WorkManager'ı kullanmak tercih edilir.

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

Not: Uygulamanız API düzeyi 26 veya üstünü hedefliyorsa uygulamanın kendisi ön planda değilken sistem, arka plan hizmetlerinin çalıştırılmasına kısıtlamalar uygular. Örneğin, çoğu durumda konum bilgilerine arka planda 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ğlanır. Bağlanmış bir hizmet, bileşenlerin hizmetle etkileşimde bulunması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. Hizmete aynı anda birden fazla bileşen bağlanabilir ancak tümünün bağlantısı kaldırıldığında hizmet kaldırılır.

Bu belgelerde 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üresiz olarak çalıştırılacak şekilde) ve bağlamaya izin verilir. Bu sadece birkaç geri çağırma yöntemini uygulayıp uygulamamanıza bağlıdır: 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 iki durumda olması fark etmeksizin, 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.

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

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

Ana iş parçanızın dışında 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şturmalısınız. Örneğin, yalnızca etkinliğiniz devam ederken müzik çalmak istiyorsanız onCreate() ürününde bir ileti dizisi oluşturabilir, bu müziği onStart() ürününde çalıştırmaya başlayabilir ve onStop() ürününde durdurabilirsiniz. Ayrıca geleneksel Thread sınıfı yerine java.util.concurrent paketinden veya Kotlin eş yordamlarından iş parçacığı havuzları ve yürütücüler 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.

Bir hizmet kullandığınızda bu hizmetin varsayılan olarak uygulamanızın ana iş parçacığında çalışacağını unutmayın. Bu nedenle, hizmet yoğun veya engelleme gerektiren 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 temel özelliklerini 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. Geçersiz kılmanız gereken en önemli geri çağırma yöntemleri şunlardır:

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() yöntemini çağırarak çalışması 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 istediğinde (örneğin RPC'yi gerçekleştirmek için) sistem bu yöntemi bindService() yöntemini çağırarak çağırır. Bu yöntemi uygularken, istemcilerin hizmetle iletişim kurmak için kullandığı bir arayüzü IBinder döndürerek 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 bu yöntemi, hizmet artık kullanılmadığında ve kaldırılırken çağırır. Hizmetiniz iş parçacıkları, kayıtlı işleyiciler veya alıcılar gibi kaynakları temizlemek için bunu uygulamalıdır. Bu, hizmetin aldığı son çağrıdır.

Bir bileşen, startService() yöntemini çağırarak hizmeti başlatırsa (bu işlem onStartCommand() çağrısıyla sonuçlanır) stopSelf() ile kendiliğinden durana veya başka bir bileşen stopService() yöntemini çağırarak hizmeti durdurana kadar çalışmaya devam eder.

Bir bileşen hizmeti oluşturmak için bindService() çağrısı yaparsa ve onStartCommand() çağrılanmazsa hizmet yalnızca bileşen kendisine bağlı olduğu sürece çalışır. Tüm istemcilerinin bağlantısı kaldırıldıktan sonra sistem hizmeti yok eder.

Android sistemi, yalnızca bellek düşük olduğunda hizmeti durdurur ve kullanıcı odağı olan etkinlik için sistem kaynaklarını kurtarmalıdır. Hizmet, kullanıcı odaklı 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ılmış ve uzun süredir çalışıyorsa sistem zamanla arka plan görevleri listesindeki konumunu düşürür ve hizmetin öldürmeye açık hale gelmesi son derece olasıdır. Hizmetiniz başlatıldıysa sistem tarafından yapılan yeniden başlatma işlemlerini sorunsuz şekilde ele alacak ş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 Processes and Threading (İşlemler ve İş Parçacığı) dokümanına bakın.

İlerleyen bölümlerde startService() ve bindService() hizmet yöntemlerini nasıl oluşturabileceğinizi ve bunları diğer uygulama bileşenlerinden nasıl kullanacağınızı öğreneceksiniz.

Manifest dosyasında hizmet tanımlama

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

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

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

Manifest'te hizmetinizi beyan etme 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; hizmetin sınıf adını belirtir. Uygulamanızı yayınladıktan sonra, hizmeti başlatmak veya bağlamak üzere açık amaçlara bağımlılık nedeniyle kod kırma riskini önlemek için bu adı olduğu gibi 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 daima açık niyet kullanın ve hizmetleriniz için intent filtreleri beyan etmeyin. Amaca yanıt veren hizmetten emin olamayacağınız ve kullanıcı hangi hizmetin başladığını göremeyeceğiniz için bir hizmeti başlatmak için dolaylı niyet kullanmak güvenlik açısından risk oluşturur. Android 5.0 (API düzeyi 21) sürümünden itibaren, bindService() uygulamasını dolaylı bir niyetle çağırırsanız sistem bir istisna oluşturur.

android:exported özelliğini dahil edip false olarak ayarlayarak hizmetinizin yalnızca uygulamanız tarafından kullanılabildiğinden emin olabilirsiniz. Bu işlem, açık bir amaç kullanılsa bile diğer uygulamaların hizmetinizi başlatmasını etkili bir şekilde durdurur.

Not: Kullanıcılar, cihazlarında hangi hizmetlerin çalışmakta olduğunu görebilir. Tanımadıkları veya güvenmedikleri bir hizmet görürlerse 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üne hizmetin ne yaptığını ve sunduğu avantajları açıklayan kısa bir cümle ekleyin.

Başlatılmış hizmet oluşturma

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

Bir hizmet başlatıldığında, onu başlatan bileşenden bağımsız bir yaşam döngüsüne sahiptir. Hizmet, hizmeti başlatan bileşen yok edilmiş olsa bile arka planda süresiz olarak çalışabilir. Bu durumda, işi tamamlandığında hizmetin stopSelf() yöntemini çağırarak kendisini durdurması veya başka bir bileşen stopService() yöntemini çağırarak hizmeti durdurabilir.

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

Örneğin, bir etkinliğin çevrimiçi bir veritabanına bazı veriler kaydetmesi gerektiğini varsayalım. Etkinlik bir tamamlayıcı hizmet başlatabilir ve startService() işlevine amaç ileterek bu hizmeti kaydetmek üzere verileri yayınlayabilir. Hizmet, onStartCommand() içindeki niyeti 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 söz konusu uygulamanın ana iş parçacığından çalışır. Kullanıcı aynı uygulamadan bir etkinlikle etkileşimde bulunurken yoğun işlemler veya engelleme işlemleri yapıyorsa hizmetiniz etkinlik performansını yavaşlatır. Uygulama performansının etkilenmemesi için hizmetin 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ış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ığı tüm etkinliklerin performansını yavaşlatabilir.

Android çerçevesi ayrıca 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. Bu sınıfın kullanılması, Arka planda yürütme sınırlarının kullanıma sunulması nedeniyle Android 8 Oreo'dan itibaren iyi çalışmayacağından yeni uygulamalarda düzgün çalışmayacağı 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 durumu için 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 plan işleme kılavuzuna bakın.

Hizmet sınıfının uzatılması

Service sınıfını her gelen niyeti 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 çağrıları işler ve çalışmayı arka plan iş parçacığında çalışan bir Handler hesabına yayınlar. IntentService ile aynı şekilde çalışır ve tüm istekleri art arda işler. Örneğin, aynı anda birden fazla istek çalıştırmak istiyorsanız, kodu bir iş parçacığı havuzunda çalıştırmak için değiştirebilirsiniz.

onStartCommand() yönteminin bir tam sayı döndürmesi gerektiğini unutmayın. Tam sayı, sistemin hizmeti sonlandırması durumunda sisteme nasıl devam edeceğ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() geri döndükten sonra sistem hizmeti sonlandırırsa beklemede olan teslim tarihleri olmadığı sürece hizmeti yeniden oluşturmayın. Bu, gerekli olmadığında ve uygulamanızın 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() hizmetini boş niyetle çağırır. Bu durumda bu amaçlar gerçekleşir. Bu, komut 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
onStartCommand() geri döndükten sonra sistem hizmeti sonlandırırsa hizmeti yeniden oluşturun ve hizmete gönderilen son niyetle onStartCommand() yöntemini çağırın. Bekleyen tüm amaçlar da sırayla teslim edilir. Bu seçenek, dosya indirme gibi aktif bir şekilde hemen devam ettirilmesi gereken bir işi yürüten hizmetler için uygundur.

Bu döndürülen değerler hakkında daha fazla bilgi için her bir sabit değer için bağlantılı referans belgelerine bakın.

Hizmet başlatma

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

Not: Uygulamanız API düzeyi 26 veya üstünü hedefliyorsa sistem, uygulamanın kendisi ön planda değilse arka plan hizmetlerinin kullanımı veya oluşturulmasıyla ilgili kısıtlamalar uygular. Bir uygulamanın ön plan hizmeti oluşturması gerekiyorsa uygulama startForegroundService() yöntemini çağırmalıdır. Bu yöntem bir arka plan hizmeti oluşturur ancak yöntem, sisteme hizmetin kendisini ön plana yükselteceği sinyalini verir. Hizmet oluşturulduktan sonra beş saniye içinde startForeground() yöntemini ç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 döndürülür ve Android sistemi, hizmetin onStartCommand() yöntemini çağırır. Hizmet zaten çalışmıyorsa sistem ilk olarak onCreate() yöntemini, ardından da onStartCommand() yöntemini çağırır.

Hizmet aynı zamanda bağlama da sağlamıyorsa uygulama bileşeni ile hizmet arasındaki tek iletişim modu startService() ile sağlanan amaçtır. Bununla birlikte, hizmetin bir sonucu geri göndermesini isterseniz hizmeti başlatan istemci bir yayın için (getBroadcast() ile) bir PendingIntent oluşturabilir ve bunu hizmeti başlatan Intent içindeki hizmete sunabilir. Hizmet, daha sonra yayını kullanarak bir sonucu ulaştırabilir.

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

Bir hizmeti durdurma

Başlatılan bir hizmet kendi yaşam döngüsünü yönetmelidir. Yani sistem belleğini kurtarmak zorunda olmadığı ve onStartCommand() geri geldikten sonra hizmet çalışmaya devam etmediği sürece sistem, hizmeti durdurmaz veya kaldırmaz. Hizmet stopSelf() yöntemini çağırarak kendini durdurmalı veya başka bir bileşen stopService() yöntemini çağırarak hizmeti durdurabilir.

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

Hizmetiniz aynı anda onStartCommand() için birden fazla isteği yerine getiriyorsa yeni bir başlatma isteği almış olabileceğinizden (ilk isteğin sonunda durdurmak ikinci isteğin sonlandırılmasına neden olur) bir başlangıç isteğini işlemeyi tamamladıktan sonra hizmeti durdurmanız gerekmez. Bu sorunu önlemek amacıyla hizmeti durdurma isteğinizin her zaman en son başlatma isteğine dayalı olmasını sağlamak için stopSelf(int) kullanabilirsiniz. Diğer bir deyişle, stopSelf(int) yöntemini çağırdığınızda durdurma isteğinizin ilişkili olduğu başlatma isteğinin (onStartCommand() adresine gönderilen startId) kimliğini iletirsiniz. Hizmet, siz stopSelf(int) çağrısı yapmadan önce yeni bir başlatma isteği alırsa kimlik eşleşmez ve hizmet durmaz.

Dikkat: Sistem kaynaklarını boşa harcamamak ve pil gücü tüketmemek 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() numaralı telefona bir çağrı alırsa 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 başlıklı bölüme bakın.

Bağlı hizmet oluşturma

Bağlı hizmet, uygulama bileşenlerinin uzun süreli bağlantı oluşturmak için bindService() yöntemini çağırarak ona bağlanmasına olanak tanıyan hizmettir. 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.

Bir bağlı hizmet oluşturmak amacıyla hizmetle iletişim için arayüzü tanımlayan bir IBinder döndürmek amacıyla onBind() geri çağırma yöntemini uygulayın. Ardından diğer uygulama bileşenleri, arayüzü almak ve hizmette yöntemler çağırmaya başlamak için bindService() yöntemini çağırabilir. Hizmet yalnızca kendisine bağlı uygulama bileşenini sunmak üzere çalışır. Bu nedenle hizmete bağlı hiçbir bileşen olmadığında sistem onu yok eder. Bağlı bir hizmeti, onStartCommand() ile başlatıldığında yaptığınız şekilde durdurmanız gerekmez.

Bağlı 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 uygulamasının bir uygulaması olmalıdır ve hizmetinizin onBind() geri çağırma yönteminden döndürmesi gerekir. İstemci IBinder aldıktan sonra bu arayüz üzerinden hizmetle etkileşime geçmeye başlayabilir.

Hizmete aynı anda birden fazla istemci bağlanabilir. Bir istemci hizmetle etkileşimi tamamladığında, bağlantıyı kesmek için unbindService() yöntemini çağırır. Hizmete bağlı istemci olmadığında sistem hizmeti kaldırır.

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

Kullanıcıya bildirim gönderme

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

Snackbar bildirimi, mevcut pencerenin yüzeyinde, kaybolmadan önce yalnızca bir an için görünen mesajdır. Durum çubuğu bildirimi, kullanıcının bir işlem (etkinlik başlatmak gibi) yapmak için seçebileceği bir mesaj içeren durum çubuğunda bir simge sağlar.

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

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ği için hizmetinizin nasıl oluşturulduğuna ve yok edildiğine dikkat etmeniz daha da önemlidir.

Hizmet yaşam döngüsü, oluşturulduğu andan kullanımdan kaldırılmasına kadar şu 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 kendisini durdurması gerekir. Başka bir bileşen de stopService() yöntemini çağırarak hizmeti durdurabilir. Hizmet durdurulduğunda sistem onu kaldırır.

  • Bağlı bir hizmet

    Hizmet, başka bir bileşen (bir istemci) bindService() işlevini çağırdığında oluşturulur. Daha sonra istemci, IBinder arayüzü üzerinden hizmetle iletişim kurar. İstemci, unbindService() yöntemini çağırarak bağlantıyı kapatabilir. Birden çok istemci aynı hizmete bağlanabilir ve bunların tümü kaldırıldığında sistem hizmeti imha eder. Hizmetin kendini durdurması gerekmez.

Bu iki yol birbirinden tamamen ayrı değildir. startService() ile başlatılmış bir hizmete bağlanabilirsiniz. Örneğin, çalınacak müziği tanımlayan bir Intent ile startService() yöntemini çağırarak bir arka plan müziği hizmeti başlatabilirsiniz. Daha sonra, muhtemelen kullanıcı oynatıcı üzerinde biraz kontrol sahibi olmak veya mevcut şarkı hakkında bilgi almak istediğinde, bir etkinlik bindService() araması 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

Etkinliklerde olduğu gibi, hizmetlerde de hizmetin durumundaki değişiklikleri izlemek ve uygun zamanlarda çalışmak için uygulayabileceğiniz yaşam döngüsü geri çağırma yöntemleri vardır. Aşağıdaki iskelet hizmeti, 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 şemada, hizmetin startService() ile oluşturulduğu andaki yaşam döngüsü; sağdaki şemada ise hizmetin bindService() ile oluşturulduğu andaki yaşam döngüsü gösterilmektedir.

Şekil 2'de bir hizmetin tipik geri çağırma yöntemleri gösterilmektedir. Bu şekilde, startService() tarafından oluşturulan hizmetler ile bindService() tarafından oluşturulan hizmetler birbirinden ayrılsa da nasıl başlatılmış olursa olsun herhangi bir hizmetin, istemcilerin bu hizmete bağlanmasına izin verebileceğ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ı telefonu alabilir (bir istemci bindService() araması yaptığında).

Bu yöntemleri uygulayarak hizmet yaşam döngüsünün iç içe geçmiş şu iki döngüsünü izleyebilirsiniz:

  • Bir hizmetin tüm kullanım ömrü, onCreate() çağrısının yapıldığı saat ile onDestroy() ürününün döndüğü zaman arasında gerçekleşir. Etkinliklerde olduğu gibi, hizmetler 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() ürününde çalındığı ileti dizisini oluşturabilir ve ardından onDestroy() içindeki 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ılırsa etkin kullanım süresi, tüm kullanım ömrünün sona erdiği anda sona erer (hizmet, onStartCommand() geri döndükten sonra bile etkin olmaya devam eder). Hizmet bağlıysa etkin kullanım süresi onUnbind() geri döndüğünde sona erer.

Not: Başlatılan bir hizmet, stopSelf() veya stopService() çağrısı tarafından durdurulmuş olsa da ilgili hizmet için geri çağırma yoktur (onStop() geri çağırma yapılmaz). Hizmet bir istemciye bağlı değilse sistem, 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 Bağlı Hizmetler belgesine göz atı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.