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. Ayrıca, bir bileşen etkileşimde bulunmak 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/Ç'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 aksini belirtmediğiniz sürece ayrı bir süreçte çalışmaz. Uygulama Yanıt Vermiyor (ANR) hatalarını önlemek için 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

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

Bir ön plan hizmeti kullandığınızda, kullanıcıların hizmetin çalıştığının aktif olarak farkında olması için 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 hizmeti olarak çalıştırabilir. Çoğu durumda, doğrudan ön plan hizmetlerinin kullanılması yerine WorkManager'ın kullanılması tercih edilir.

Arka plan
Arka plan hizmeti, kullanıcı tarafından doğrudan fark edilmeyen işlemler gerçekleştirir. Örneğin, bir uygulama, depolama alanını küçültmek için bir hizmet kullanmışsa bu hizmet 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ğlanmış olur. Bağlanmış 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ğlandığı sürece çalışır. Birden fazla bileşen hizmete aynı anda bağlanabilir ancak bu bileşenlerin tümü kaldırıldığında hizmet kaldırılır.

Bu belgede genellikle başlatılan ve bağlanan hizmetler ayrı ayrı ele alınsa da hizmetiniz her iki şekilde de çalışabilir. Başlatılabilir (süresiz olarak çalıştırılabilir) ve ayrıca bağlamaya izin verilebilir. Birkaç geri çağırma yöntemi uygulayıp uygulamamanız yeterlidir: Bileşenlerin başlatmasına izin vermek için onStartCommand(), bağlamaya izin vermek için de 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 olsa) herhangi bir bileşenin bir Intent ile başlatarak bir etkinliği kullanabileceği şekilde kullanabilir. Ancak, manifest dosyasında hizmeti gizli olarak beyan edebilir ve diğer uygulamalardan erişimi engelleyebilirsiniz. Bu konu, Manifest'te hizmetin bildirilmesi hakkında daha ayrıntılı bir şekilde ele alınmaktadır.

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

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

Ana iş parçanı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 devam ederken bazı müzikler çalmak istiyorsanız onCreate() ürününde bir ileti dizisi oluşturabilir, onu onStart() ürününde çalıştırmaya başlayabilir ve onStop() içinde durdurabilirsiniz. Geleneksel Thread sınıfı yerine java.util.concurrent paketinden veya Kotlin eş yordamlarından iş parçacığı havuzlarını ve yürütücüleri de kullanabilirsiniz. Yürütmeyi arka plan iş parçacıklarına taşıma hakkında daha fazla bilgi için Android'de Threading dokümanına bakın.

Bir hizmet kullandığınızda bu hizmetin varsayılan olarak uygulamanızın ana iş parçacığında çalışmaya devam ettiğini 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 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. bir 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 süresiz olarak arka planda çalışabilir. Bunu uygularsanız çalışması tamamlandığında stopSelf() veya stopService() yöntemini çağırarak hizmeti durdurmak sizin sorumluluğunuzdadır. Yalnızca bağlama sağlamak isterseniz bu yöntemi uygulamanız gerekmez.
onBind()
Başka bir bileşen hizmete bağlanmak (ör. TBG gerçekleştirmek) istediğinde sistem bu yöntemi bindService() yöntemini çağırarak çağırır. Bu yöntemi uygulamanızda, istemcilerin IBinder döndürerek hizmetle iletişim kurmak için kullandığı bir 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() çağrılmadan ö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()
Hizmet artık kullanılmadığında ve kaldırılırken sistem 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 startService() yöntemini çağırarak hizmeti başlatırsa (bu durumda onStartCommand() çağrılır) hizmet, stopSelf() ile kendiliğinden durdurulana veya başka bir bileşen stopService() çağrısı yaparak çalışmayı durdurana kadar çalışmaya devam eder.

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

Android sistemi, bir hizmeti yalnızca bellek az olduğunda durdurur ve kullanıcı odağı 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ığı beyan edilmişse nadiren sonlandırılır. Hizmet başlatılırsa ve uzun süredir çalışıyorsa sistem zamanla arka plan görevleri listesindeki konumunu düşürür ve hizmeti devre dışı bırakmaya daha elverişli hale getirir. 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 yeniden başlatır ancak bu durum, onStartCommand() kaynağından 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.

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 bir hizmeti tanımlama

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

Hizmetinizi tanımlamak için <application> öğesinin alt öğesi olarak bir <service> öğesi 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 zorunlu 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ğlı olarak kod kırma riskini önlemek amacıyla bu adı değiştirmeyin (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 bir intent kullanın ve hizmetleriniz için intent filtreleri bildirmeyin. Bir hizmeti başlatmak için dolaylı intent'lerin kullanılması güvenlik açısından risk oluşturur. Çü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 atar.

android:exported özelliğini dahil edip false olarak ayarlayarak hizmetinizin yalnızca uygulamanızın kullanımına sunulduğundan emin olabilirsiniz. Bu işlem, açık bir niyet kullanılsa 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ü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 kısmına hizmetin işlevini ve sunduğu avantajları 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 ç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 nedenle, işi tamamlandığında hizmet stopSelf() çağrısı yaparak kendini durdurmalıdır. Başka bir bileşen ise 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 online bir veritabanına bazı veriler kaydetmesi gerektiğini varsayalım. Etkinlik, bir tamamlayıcı hizmet başlatabilir ve startService() işlevine bir amaç ileterek bu hizmetin verilerini kaydedecek verileri sunabilir. Hizmet, amacı onStartCommand() ürününde 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ı işlemde ve uygulamanın ana iş parçacığında çalışır. Kullanıcı, aynı uygulamadaki bir etkinlikle etkileşimde bulunurken yoğun işlemler 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ış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, 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 uygulanması nedeniyle Android 8 Oreo'dan itibaren iyi çalışmayacağından yeni uygulamalarda iyi çalışmayacağı için önerilmez. Ayrıca, Android 11'den itibaren kullanımdan kaldırılmıştır. Android'in yeni sürümleriyle uyumlu olan JobIntentService'i, IntentService için bir yedek olarak kullanabilirsiniz.

Aşağıdaki bölümlerde, kendi özel hizmetinizi nasıl uygulayabileceğiniz açıklanmıştı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 planda işleme kılavuzuna bakın.

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

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 aramaları işler ve çalışmayı arka plandaki bir ileti dizisinde ç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 bir iş parçacığı havuzunda çalıştıracak ş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() işlevinin döndürdüğü değer aşağıdaki sabit değerlerden biri olmalıdır:

START_NOT_STICKY
onStartCommand() döndürüldükten sonra sistem hizmeti sonlandırırsa beklemede olan yayınlama niyetleri olmadığı sürece hizmeti yeniden oluşturmayın. Bu, gerekli olmadığında hizmetinizi çalıştırmaktan kaçınmak için ve uygulamanız henüz tamamlanmamış işleri yeniden başlatabiliyorsa onu ç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() yöntemini çağırın ancak son amacı yeniden teslim etmeyin. Bunun yerine, hizmeti başlatmak için bekleyen amaçlar yoksa sistem onStartCommand() hizmetini 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() yöntemini çağırın. Beklemedeki tüm amaçlar sırayla teslim edilir. Bu, dosya indirme gibi hemen devam ettirilmesi gereken bir işi etkin olarak yürüten hizmetler için uygundur.

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

Hizmet başlatma

Intent öğesini startService() veya startForegroundService() öğesine geçirerek bir etkinlik veya başka bir uygulama bileşeninden hizmet başlatabilirsiniz. Android sistemi, hizmetin onStartCommand() yöntemini çağırır ve bunu, 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 olmadığı sürece arka plan hizmetlerinin kullanımı veya oluşturulmasıyla ilgili kısıtlamalar uygular. Bir uygulamanın bir ön plan hizmeti oluşturması gerekiyorsa uygulama, startForegroundService() işlevini çağırmalıdır. Bu yöntem bir arka plan hizmeti oluşturur ancak yöntem, sisteme hizmetin kendisini ön plana yükselteceğini bildirir. Hizmet oluşturulduktan sonra, hizmet beş saniye içinde startForeground() yöntemini çağırmalıdır.

Örneğin, bir etkinlik, önceki bölümde (HelloService) startService() ile açık bir amaç kullanarak örnek hizmeti burada gösterildiği gibi 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() yöntemini, ardından 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 sunulan amaç olur. 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 gönderebilir. Ardından hizmet, yayını kullanarak bir sonuç elde edebilir.

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 tek bir istek (stopSelf() veya stopService() ile) 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 ve onStartCommand() geri döndükten sonra hizmet çalışmaya devam etmediği sürece sistem, hizmeti durdurmaz veya kaldırmaz. Hizmetin stopSelf() yöntemini çağırarak kendisini durdurması gerekir. Aksi takdirde başka bir bileşen stopService() yöntemini ç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() için birden fazla isteği gerçekleştiriyorsa yeni bir başlatma isteği almış olabileceğinizden, bir başlatma isteğini işlemeyi bitirdiğinizde hizmeti durdurmamanız gerekir (ilk isteğin sonunda durdurmak ikinci isteği de sonlandırır). Bu sorunu önlemek için stopSelf(int) kullanarak hizmeti durdurma isteğinizin her zaman en son başlatma isteğine dayalı olmasını sağlayabilirsiniz. Yani stopSelf(int) yöntemini çağırdığınızda durdurma isteğinizin karşılık geldiği başlatma isteğinin (onStartCommand()'a gönderilen startId) kimliğini iletirsiniz. Bu durumda hizmet, stopSelf(int) çağrısını gerçekleştirmeden ö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() yöntemini çağırarak hizmeti durdurabilir. Hizmet için bağlamayı etkinleştirseniz bile, onStartCommand() 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 bölümüne bakın.

Bağlı hizmet oluşturma

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

Uygulamanızdaki etkinliklerden 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ğlanmış hizmet oluşturmak için onBind() geri çağırma yöntemini uygulayarak hizmetle iletişimde kullanılacak arayüzü tanımlayan bir IBinder döndürülmesini sağlayın. 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 için çalışır. Bu nedenle, hizmete bağlı herhangi bir bileşen olmadığında sistem hizmeti yok eder. Bağlı bir hizmeti, hizmet onStartCommand() tarihine kadar başlatıldığında yaptığınız gibi durdurmanız gerekmez.

Bağlanmış 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ürdüğü arayüzdür. İstemci IBinder aldıktan sonra bu arayüz üzerinden hizmetle etkileşimde bulunmaya başlayabilir.

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

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 görüşmesi Sınır Hizmetleri 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 kullanıcıya etkinlikleri bildirebilir.

Snackbar bildirimi, mevcut pencerenin yüzeyinde, kaybolmadan önce yalnızca bir an için görünen mesajdır. Durum çubuğu bildirimi, durum çubuğunda bir mesaj içeren simge sağlar. Kullanıcı, bu simgeyi seçerek bir işlem (ör. etkinlik başlatma) gerçekleştirebilir.

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

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 hizmetler, kullanıcının farkında olmadan arka planda çalışabileceğinden hizmetinizin nasıl oluşturulduğuna ve yok edildiğine dikkat etmeniz daha da önemlidir.

Hizmet yaşam döngüsü (oluşturulmasından yok edildiği ana kadar) şu iki yoldan birini takip edebilir:

  • Başlatılmış bir hizmet

    Başka bir bileşen startService() çağırdığında hizmet 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() çağrısı yaparak hizmeti durdurabilir. Hizmet durdurulduğunda, sistem hizmeti imha eder.

  • Bağlı hizmet

    Başka bir bileşen (bir istemci) bindService() çağırdığında hizmet oluşturulur. Ardından 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 ve tüm istemciler bağlantıyı kaldırdığınızda sistem hizmeti yok 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() işlevini çağırarak bir arka plan müziği hizmeti başlatabilirsiniz. Daha sonra, muhtemelen kullanıcı oynatıcı üzerinde bir miktar kontrole sahip olmak veya mevcut şarkı hakkında bilgi almak istediğinde etkinlik, bindService() yöntemini çağırarak 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

Bir hizmette olduğu gibi, hizmetin durumundaki değişiklikleri izlemek ve uygun zamanlarda iş gerçekleştirmek için uygulayabileceğiniz yaşam döngüsü geri çağırma yöntemleri vardır. 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 diyagramda hizmet startService() ile oluşturulduğunda 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 hizmet için 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 herhangi bir hizmetin, nasıl başlatılmış olursa olsun istemcilerin 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 hizmetin yaşam döngüsündeki şu iki iç içe geçmiş döngüsünü izleyebilirsiniz:

  • Bir hizmetin tüm kullanım ömrü, onCreate() çağrısının yapıldığı zaman ile onDestroy() ürününün döndürdüğü zaman arasında gerçekleşir. Tıpkı etkinliklerde olduğu gibi, bir 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() içinde ç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ına bakılmaksızın 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() öğesine geçirilen Intent verilir.

    Hizmet başlatılırsa etkin kullanım ömrü, tüm kullanım ömrü boyunca 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 süresi 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 yapılmaz). Hizmet bir istemciye bağlı değilse hizmet durdurulduğunda sistem tarafından kaldırılır. Alınan tek geri arama onDestroy() olur.

Bağlama sağlayan bir hizmet oluşturma hakkında daha fazla bilgi edinmek için 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 bilginin yer aldığı Sınır Hizmetleri belgesine bakın.