Ringkasan layanan

Service adalah komponen aplikasi yang dapat menjalankan operasi yang berjalan lama di latar belakang. API ini tidak menyediakan antarmuka pengguna. Setelah dimulai, layanan mungkin terus berjalan selama beberapa waktu, bahkan setelah pengguna beralih ke aplikasi lain. Selain itu, komponen dapat terikat ke layanan untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan dapat menangani transaksi jaringan, memutar musik, melakukan I/O file, atau berinteraksi dengan penyedia konten, semuanya dari latar belakang.

Perhatian: Layanan berjalan di thread utama proses hostingnya; layanan tidak membuat thread-nya sendiri dan tidak berjalan dalam proses terpisah kecuali jika Anda menentukan sebaliknya. Anda harus menjalankan operasi pemblokiran apa pun di thread terpisah dalam layanan untuk menghindari error Aplikasi Tidak Merespons (ANR).

Jenis Layanan

Inilah tiga tipe layanan yang berbeda:

Latar depan

Layanan latar depan melakukan beberapa operasi yang terlihat oleh pengguna. Misalnya, aplikasi audio akan menggunakan layanan latar depan untuk memutar trek audio. Layanan latar depan harus menampilkan Notifikasi. Layanan latar depan terus berjalan meskipun pengguna tidak berinteraksi dengan aplikasi.

Saat menggunakan layanan latar depan, Anda harus menampilkan notifikasi agar pengguna secara aktif mengetahui bahwa layanan sedang berjalan. Notifikasi ini tidak dapat ditutup kecuali jika layanan dihentikan atau dihapus dari latar depan.

Pelajari lebih lanjut cara mengonfigurasi layanan latar depan di aplikasi Anda.

Catatan: WorkManager API menawarkan cara yang fleksibel untuk menjadwalkan tugas, dan dapat menjalankan tugas ini sebagai layanan latar depan jika diperlukan. Dalam banyak kasus, sebaiknya gunakan WorkManager daripada menggunakan layanan latar depan secara langsung.

Latar belakang
Layanan latar belakang menjalankan operasi yang tidak langsung diketahui oleh pengguna. Misalnya, jika aplikasi menggunakan layanan untuk memadatkan penyimpanannya, layanan tersebut biasanya merupakan layanan latar belakang.

Catatan: Jika aplikasi Anda menargetkan API level 26 atau yang lebih tinggi, sistem akan menerapkan pembatasan pada layanan latar belakang yang berjalan saat aplikasi itu sendiri tidak berada di latar depan. Dalam sebagian besar situasi, misalnya, Anda tidak boleh mengakses informasi lokasi dari latar belakang. Sebagai gantinya, jadwalkan tugas menggunakan WorkManager.

Terikat
Layanan terikat saat komponen aplikasi terikat dengannya dengan memanggil bindService(). Layanan terikat menawarkan antarmuka klien-server yang memungkinkan komponen berinteraksi dengan layanan, mengirim permintaan, menerima hasil, dan bahkan melakukannya di seluruh proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama komponen aplikasi lain terikat dengannya. Beberapa komponen dapat terikat ke layanan sekaligus, tetapi jika semuanya terbebas, layanan akan dihancurkan.

Meskipun dokumentasi ini umumnya membahas layanan yang dimulai dan terikat secara terpisah, layanan Anda dapat berfungsi dengan dua cara—dapat dimulai (untuk berjalan tanpa batas waktu) dan juga memungkinkan pengikatan. Hanya masalah apakah Anda menerapkan beberapa metode callback: onStartCommand() untuk mengizinkan komponen memulainya dan onBind() untuk mengizinkan binding.

Terlepas dari apakah layanan Anda dimulai, terikat, atau keduanya, komponen aplikasi apa pun dapat menggunakan layanan (bahkan dari aplikasi terpisah) dengan cara yang sama seperti komponen apa pun dapat menggunakan aktivitas—dengan memulainya dengan Intent. Namun, Anda dapat mendeklarasikan layanan sebagai pribadi dalam file manifes dan memblokir akses dari aplikasi lain. Hal ini dibahas lebih lanjut di bagian tentang Mendeklarasikan layanan dalam manifes.

Memilih antara layanan dan thread

Layanan hanyalah komponen yang dapat berjalan di latar belakang, meskipun saat pengguna tidak berinteraksi dengan aplikasi Anda, jadi Anda harus membuat layanan hanya jika itu yang Anda butuhkan.

Jika Anda harus melakukan pekerjaan di luar thread utama, tetapi hanya saat pengguna berinteraksi dengan aplikasi Anda, Anda harus membuat thread baru dalam konteks komponen aplikasi lain. Misalnya, jika ingin memutar beberapa musik, tetapi hanya saat aktivitas berjalan, Anda dapat membuat thread di onCreate(), mulai menjalankannya di onStart(), dan menghentikannya di onStop(). Pertimbangkan juga untuk menggunakan kumpulan thread dan eksekutor dari paket java.util.concurrent atau coroutine Kotlin, bukan class Thread tradisional. Lihat dokumen Threading di Android untuk mengetahui informasi selengkapnya tentang memindahkan eksekusi ke thread latar belakang.

Ingat bahwa jika Anda menggunakan layanan, layanan tersebut masih berjalan di thread utama aplikasi secara default, sehingga Anda tetap harus membuat thread baru dalam layanan jika layanan tersebut melakukan operasi yang intensif atau memblokir.

Dasar-dasar

Untuk membuat layanan, Anda harus membuat subclass Service atau menggunakan salah satu subclass yang ada. Dalam implementasi, Anda harus mengganti beberapa metode callback yang menangani aspek utama siklus proses layanan dan menyediakan mekanisme yang memungkinkan komponen terikat ke layanan, jika sesuai. Berikut adalah metode callback terpenting yang harus Anda ganti:

onStartCommand()
Sistem memanggil metode ini dengan memanggil startService() saat komponen lain (seperti aktivitas) meminta layanan dimulai. Saat metode ini dieksekusi, layanan akan dimulai dan dapat berjalan di latar belakang tanpa batas waktu. Jika Anda menerapkannya, Anda bertanggung jawab untuk menghentikan layanan saat tugasnya selesai dengan memanggil stopSelf() atau stopService(). Jika hanya ingin menyediakan binding, Anda tidak perlu menerapkan metode ini.
onBind()
Sistem memanggil metode ini dengan memanggil bindService() saat komponen lain ingin mengikat dengan layanan (seperti untuk melakukan RPC). Dalam penerapan metode ini, Anda harus menyediakan antarmuka yang digunakan klien untuk berkomunikasi dengan layanan dengan menampilkan IBinder. Anda harus selalu menerapkan metode ini; namun, jika tidak ingin mengizinkan binding, Anda harus menampilkan null.
onCreate()
Sistem memanggil metode ini untuk melakukan prosedur penyiapan satu kali saat layanan dibuat pada awalnya (sebelum memanggil onStartCommand() atau onBind()). Jika layanan sudah berjalan, metode ini tidak dipanggil.
onDestroy()
Sistem memanggil metode ini saat layanan tidak lagi digunakan dan dihancurkan. Layanan Anda harus menerapkannya untuk membersihkan resource apa pun seperti thread, pemroses terdaftar, atau penerima. Ini adalah panggilan terakhir yang diterima layanan.

Jika komponen memulai layanan dengan memanggil startService() (yang menghasilkan panggilan ke onStartCommand()), layanan akan terus berjalan hingga berhenti dengan stopSelf() atau komponen lain menghentikannya dengan memanggil stopService().

Jika komponen memanggil bindService() untuk membuat layanan dan onStartCommand() tidak dipanggil, layanan hanya berjalan selama komponen terikat dengannya. Setelah layanan dilepas ikatannya dari semua kliennya, sistem akan menghapusnya.

Sistem Android menghentikan layanan hanya jika memori rendah dan harus memulihkan resource sistem untuk aktivitas yang memiliki fokus pengguna. Jika terikat dengan aktivitas yang memiliki fokus pengguna, layanan tersebut cenderung tidak akan dihentikan; jika layanan dideklarasikan untuk berjalan di latar depan, layanan tersebut jarang dihentikan. Jika layanan dimulai dan berjalan lama, sistem akan menurunkan posisinya dalam daftar tugas latar belakang dari waktu ke waktu, dan layanan menjadi sangat rentan terhadap penghentian—jika layanan dimulai, Anda harus mendesainnya untuk menangani mulai ulang oleh sistem dengan baik. Jika sistem menghentikan layanan Anda, sistem akan memulai ulang layanan tersebut segera setelah resource tersedia, tetapi hal ini juga bergantung pada nilai yang Anda kembalikan dari onStartCommand(). Untuk mengetahui informasi selengkapnya tentang kapan sistem mungkin menghancurkan layanan, lihat dokumen Proses dan Threading.

Di bagian berikut, Anda akan melihat cara membuat metode layanan startService() dan bindService(), serta cara menggunakannya dari komponen aplikasi lain.

Mendeklarasikan layanan dalam manifes

Anda harus mendeklarasikan semua layanan dalam file manifes aplikasi, seperti yang Anda lakukan untuk aktivitas dan komponen lainnya.

Untuk mendeklarasikan layanan, tambahkan elemen <service> sebagai turunan dari elemen <application>. Berikut ini contohnya:

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

Lihat referensi elemen <service> untuk mengetahui informasi selengkapnya tentang mendeklarasikan layanan Anda dalam manifes.

Ada atribut lain yang dapat Anda sertakan dalam elemen <service> untuk menentukan properti seperti izin yang diperlukan untuk memulai layanan dan proses tempat layanan harus berjalan. Atribut android:name adalah satu-satunya atribut yang diperlukan—atribut ini menentukan nama class layanan. Setelah memublikasikan aplikasi, jangan ubah nama ini untuk menghindari risiko kerusakan kode karena bergantung pada intent eksplisit untuk memulai atau mengikat layanan (baca postingan blog, Hal-Hal yang Tidak Dapat Diubah).

Perhatian: Untuk memastikan aplikasi Anda aman, selalu gunakan intent eksplisit saat memulai Service dan jangan deklarasikan filter intent untuk layanan Anda. Menggunakan intent implisit untuk memulai layanan dapat menimbulkan bahaya keamanan karena Anda tidak dapat memastikan layanan yang merespons intent tersebut, dan pengguna tidak dapat melihat layanan yang dimulai. Mulai dari Android 5.0 (API level 21), sistem akan menampilkan pengecualian jika Anda memanggil bindService() dengan intent implisit.

Anda dapat memastikan bahwa layanan hanya tersedia untuk aplikasi Anda dengan menyertakan atribut android:exported dan menyetelnya ke false. Tindakan ini secara efektif menghentikan aplikasi lain untuk memulai layanan Anda, meskipun menggunakan intent eksplisit.

Catatan: Pengguna dapat melihat layanan yang berjalan di perangkat mereka. Jika melihat layanan yang tidak dikenali atau tidak dipercaya, pengguna dapat menghentikan layanan tersebut. Agar layanan tidak dihentikan secara tidak sengaja oleh pengguna, Anda perlu menambahkan atribut android:description ke elemen <service> dalam manifes aplikasi. Dalam deskripsi, berikan kalimat singkat yang menjelaskan fungsi layanan dan manfaat yang diberikannya.

Membuat layanan yang sudah dimulai

Layanan yang dimulai adalah layanan yang dimulai oleh komponen lain dengan memanggil startService(), yang menghasilkan panggilan ke metode onStartCommand() layanan.

Saat dimulai, layanan memiliki siklus proses yang tidak bergantung pada komponen yang memulainya. Layanan dapat berjalan di latar belakang tanpa batas waktu, meskipun komponen yang memulainya dihancurkan. Dengan demikian, layanan harus berhenti sendiri saat tugasnya selesai dengan memanggil stopSelf(), atau komponen lain dapat menghentikannya dengan memanggil stopService().

Komponen aplikasi seperti aktivitas dapat memulai layanan dengan memanggil startService() dan meneruskan Intent yang menentukan layanan dan menyertakan data apa pun untuk digunakan layanan. Layanan menerima Intent ini dalam metode onStartCommand().

Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas dapat memulai layanan pendamping dan mengirimkan data yang akan disimpan dengan meneruskan intent ke startService(). Layanan menerima intent di onStartCommand(), terhubung ke Internet, dan melakukan transaksi database. Setelah transaksi selesai, layanan akan berhenti sendiri dan dihancurkan.

Perhatian: Layanan berjalan dalam proses yang sama dengan aplikasi tempat layanan dideklarasikan dan di thread utama aplikasi tersebut secara default. Jika layanan Anda melakukan operasi intensif atau pemblokiran saat pengguna berinteraksi dengan aktivitas dari aplikasi yang sama, layanan akan memperlambat performa aktivitas. Untuk menghindari dampak pada performa aplikasi, mulai thread baru di dalam layanan.

Class Service adalah class dasar untuk semua layanan. Saat Anda memperluas class ini, Anda harus membuat thread baru tempat layanan dapat menyelesaikan semua tugasnya; layanan menggunakan thread utama aplikasi secara default, yang dapat memperlambat performa aktivitas apa pun yang dijalankan aplikasi Anda.

Framework Android juga menyediakan subclass IntentService dari Service yang menggunakan thread pekerja untuk menangani semua permintaan mulai, satu per satu. Penggunaan class ini tidak direkomendasikan untuk aplikasi baru karena tidak akan berfungsi dengan baik mulai Android 8 Oreo, karena diperkenalkannya Batas eksekusi latar belakang. Selain itu, fitur ini tidak digunakan lagi mulai Android 11. Anda dapat menggunakan JobIntentService sebagai pengganti IntentService yang kompatibel dengan versi Android yang lebih baru.

Bagian berikut menjelaskan cara menerapkan layanan kustom Anda sendiri, tetapi sebaiknya Anda mempertimbangkan untuk menggunakan WorkManager untuk sebagian besar kasus penggunaan. Lihat panduan pemrosesan di latar belakang di Android untuk mengetahui apakah ada solusi yang sesuai dengan kebutuhan Anda.

Memperluas class Layanan

Anda dapat memperluas class Service untuk menangani setiap intent yang masuk. Berikut tampilan penerapan dasar:

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();
  }
}

Contoh kode menangani semua panggilan masuk di onStartCommand() dan memposting pekerjaan ke Handler yang berjalan di thread latar belakang. Fungsi ini berfungsi seperti IntentService dan memproses semua permintaan secara serial, satu per satu. Anda dapat mengubah kode untuk menjalankan tugas di kumpulan thread, misalnya, jika ingin menjalankan beberapa permintaan secara bersamaan.

Perhatikan bahwa metode onStartCommand() harus menampilkan bilangan bulat. Bilangan bulat adalah nilai yang menjelaskan cara sistem melanjutkan layanan jika sistem menghentikannya. Nilai yang ditampilkan dari onStartCommand() harus berupa salah satu konstanta berikut:

START_NOT_STICKY
Jika sistem menghentikan layanan setelah onStartCommand() ditampilkan, jangan buat ulang layanan kecuali jika ada intent yang tertunda untuk dikirim. Ini adalah opsi paling aman untuk menghindari pengoperasian layanan saat tidak diperlukan dan saat aplikasi Anda dapat memulai ulang tugas yang belum selesai.
START_STICKY
Jika sistem menghentikan layanan setelah onStartCommand() ditampilkan, buat ulang layanan dan panggil onStartCommand(), tetapi jangan kirim ulang intent terakhir. Sebagai gantinya, sistem memanggil onStartCommand() dengan intent null kecuali jika ada intent tertunda untuk memulai layanan. Dalam hal ini, intent tersebut akan dikirim. Hal ini cocok untuk pemutar media (atau layanan serupa) yang tidak menjalankan perintah, tetapi berjalan tanpa batas waktu dan menunggu tugas.
START_REDELIVER_INTENT
Jika sistem menghentikan layanan setelah onStartCommand() ditampilkan, buat ulang layanan dan panggil onStartCommand() dengan intent terakhir yang dikirim ke layanan. Intent yang tertunda akan disampaikan pada gilirannya. Hal ini cocok untuk layanan yang secara aktif melakukan tugas yang harus segera dilanjutkan, seperti mendownload file.

Untuk mengetahui detail selengkapnya tentang nilai yang ditampilkan ini, lihat dokumentasi referensi tertaut untuk setiap konstanta.

Memulai layanan

Anda dapat memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan Intent ke startService() atau startForegroundService(). Sistem Android memanggil metode onStartCommand() layanan dan meneruskan Intent, yang menentukan layanan mana yang akan dimulai.

Catatan: Jika aplikasi Anda menargetkan API level 26 atau yang lebih tinggi, sistem akan memberlakukan batasan penggunaan atau pembuatan layanan latar belakang, kecuali jika aplikasi itu sendiri berada di latar depan. Jika aplikasi perlu membuat layanan latar depan, aplikasi harus memanggil startForegroundService(). Metode tersebut membuat layanan latar belakang, tetapi metode tersebut memberi sinyal ke sistem bahwa layanan akan mempromosikan dirinya ke latar depan. Setelah dibuat, layanan harus memanggil metode startForeground() dalam waktu lima detik.

Misalnya, aktivitas dapat memulai contoh layanan di bagian sebelumnya (HelloService) menggunakan intent eksplisit dengan startService(), seperti yang ditunjukkan di sini:

Kotlin

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

Java

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

Metode startService() akan langsung ditampilkan, dan sistem Android akan memanggil metode onStartCommand() layanan. Jika layanan belum berjalan, sistem akan memanggil onCreate() terlebih dahulu, lalu memanggil onStartCommand().

Jika layanan juga tidak menyediakan binding, intent yang dikirimkan dengan startService() adalah satu-satunya mode komunikasi antara komponen aplikasi dan layanan. Namun, jika Anda ingin layanan mengirim hasil kembali, klien yang memulai layanan dapat membuat PendingIntent untuk siaran (dengan getBroadcast()) dan mengirimkannya ke layanan di Intent yang memulai layanan. Layanan ini kemudian dapat menggunakan siaran untuk memberikan hasil.

Beberapa permintaan untuk memulai layanan akan menghasilkan beberapa panggilan yang sesuai ke onStartCommand() layanan. Namun, hanya satu permintaan untuk menghentikan layanan (dengan stopSelf() atau stopService()) yang diperlukan untuk menghentikannya.

Menghentikan layanan

Layanan yang sudah dimulai harus mengelola daur hidupnya sendiri. Artinya, sistem tidak menghentikan atau menghancurkan layanan kecuali jika harus memulihkan memori sistem dan layanan terus berjalan setelah onStartCommand() ditampilkan. Layanan harus berhenti sendiri dengan memanggil stopSelf(), atau komponen lain dapat menghentikannya dengan memanggil stopService().

Setelah diminta untuk berhenti dengan stopSelf() atau stopService(), sistem akan menghapus layanan sesegera mungkin.

Jika layanan Anda menangani beberapa permintaan ke onStartCommand() secara serentak, Anda tidak boleh menghentikan layanan setelah selesai memproses permintaan mulai, karena Anda mungkin telah menerima permintaan mulai baru (berhenti di akhir permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari masalah ini, Anda dapat menggunakan stopSelf(int) untuk memastikan bahwa permintaan untuk menghentikan layanan selalu didasarkan pada permintaan mulai terbaru. Artinya, saat memanggil stopSelf(int), Anda meneruskan ID permintaan mulai (startId yang dikirim ke onStartCommand()) yang sesuai dengan permintaan berhenti Anda. Kemudian, jika layanan menerima permintaan mulai baru sebelum Anda dapat memanggil stopSelf(int), ID tidak akan cocok dan layanan tidak akan berhenti.

Perhatian: Untuk menghindari pemborosan resource sistem dan konsumsi daya baterai, pastikan aplikasi Anda menghentikan layanannya setelah selesai bekerja. Jika perlu, komponen lain dapat menghentikan layanan dengan memanggil stopService(). Meskipun Anda mengaktifkan binding untuk layanan, Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke onStartCommand().

Untuk informasi selengkapnya tentang siklus proses layanan, lihat bagian di bawah tentang Mengelola Siklus Proses Layanan.

Membuat layanan terikat

Layanan terikat adalah layanan yang memungkinkan komponen aplikasi mengikat ke layanan tersebut dengan memanggil bindService() untuk membuat koneksi yang sudah lama ada. Umumnya, komponen tidak diizinkan untuk memulainya dengan memanggil startService().

Buat layanan terikat saat Anda ingin berinteraksi dengan layanan dari aktivitas dan komponen lain dalam aplikasi atau mengekspos beberapa fungsi aplikasi ke aplikasi lain melalui komunikasi antarproses (IPC).

Untuk membuat layanan terikat, terapkan metode callback onBind() untuk menampilkan IBinder yang menentukan antarmuka untuk komunikasi dengan layanan. Komponen aplikasi lainnya kemudian dapat memanggil bindService() untuk mengambil antarmuka dan mulai memanggil metode di layanan. Layanan hanya aktif untuk melayani komponen aplikasi yang terikat dengannya, sehingga saat tidak ada komponen yang terikat ke layanan, sistem akan menghancurkannya. Anda tidak perlu menghentikan layanan terikat dengan cara yang sama seperti yang harus Anda lakukan saat layanan dimulai melalui onStartCommand().

Untuk membuat layanan terikat, Anda harus menentukan antarmuka yang menentukan cara klien dapat berkomunikasi dengan layanan. Antarmuka antara layanan dan klien ini harus merupakan implementasi IBinder dan merupakan hal yang harus dikembalikan layanan Anda dari metode callback onBind(). Setelah menerima IBinder, klien dapat mulai berinteraksi dengan layanan melalui antarmuka tersebut.

Beberapa klien bisa mengikat ke layanan sekaligus. Saat klien selesai berinteraksi dengan layanan, klien akan memanggil unbindService() untuk melepaskan ikatan. Bila tidak ada klien yang terikat pada layanan, sistem akan menghapus layanan tersebut.

Ada beberapa cara untuk menerapkan layanan terikat, dan penerapannya lebih rumit daripada layanan yang dimulai. Karena alasan ini, diskusi layanan terikat muncul dalam dokumen terpisah tentang Layanan Terikat.

Mengirim notifikasi ke pengguna

Saat berjalan, layanan dapat memberi tahu pengguna tentang peristiwa menggunakan notifikasi snackbar atau notifikasi status bar.

Notifikasi snackbar adalah pesan yang muncul di permukaan jendela saat ini hanya sesaat sebelum menghilang. Notifikasi status bar memberikan ikon di status bar dengan pesan, yang dapat dipilih pengguna untuk mengambil tindakan (seperti memulai aktivitas).

Biasanya, notifikasi status bar adalah teknik terbaik yang digunakan saat pekerjaan latar belakang seperti download file telah selesai, dan pengguna kini dapat menindaklanjutinya. Saat pengguna memilih notifikasi dari tampilan yang diluaskan, notifikasi dapat memulai aktivitas (seperti untuk menampilkan file yang didownload).

Mengelola daur hidup layanan

Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Namun, lebih penting lagi jika Anda memperhatikan dengan cermat cara layanan dibuat dan dihancurkan karena layanan dapat berjalan di latar belakang tanpa diketahui pengguna.

Siklus proses layanan—dari saat dibuat hingga dihancurkan—dapat mengikuti salah satu dari dua jalur berikut:

  • Layanan yang sudah dimulai

    Layanan dibuat saat komponen lain memanggil startService(). Layanan kemudian berjalan tanpa batas waktu dan harus berhenti sendiri dengan memanggil stopSelf(). Komponen lain juga dapat menghentikan layanan dengan memanggil stopService(). Bila layanan dihentikan, sistem akan memusnahkannya.

  • Layanan terikat

    Layanan dibuat saat komponen lain (klien) memanggil bindService(). Klien kemudian berkomunikasi dengan layanan melalui antarmuka IBinder. Klien dapat menutup koneksi dengan memanggil unbindService(). Beberapa klien dapat terikat ke layanan yang sama dan saat semuanya dilepas ikatannya, sistem akan menghapus layanan. Layanan tidak perlu berhenti dengan sendirinya.

Kedua jalur ini tidak sepenuhnya terpisah. Anda dapat mengikat ke layanan yang sudah dimulai dengan startService(). Misalnya, Anda dapat memulai layanan musik latar belakang dengan memanggil startService() dengan Intent yang mengidentifikasi musik yang akan diputar. Kemudian, mungkin saat pengguna ingin menggunakan beberapa kontrol atas pemutar atau mendapatkan informasi tentang lagu saat ini, aktivitas dapat mengikat ke layanan dengan memanggil bindService(). Dalam kasus seperti ini, stopService() atau stopSelf() tidak benar-benar menghentikan layanan hingga semua klien terbebas.

Mengimplementasikan callback daur hidup

Seperti aktivitas, layanan memiliki metode callback siklus proses yang dapat Anda terapkan untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan kerangka berikut menunjukkan setiap metode siklus proses:

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
    }
}

Catatan: Tidak seperti metode callback siklus proses aktivitas, Anda tidak diwajibkan untuk memanggil implementasi superclass dari metode callback ini.

Gambar 2. Daur hidup layanan. Diagram di sebelah kiri menunjukkan siklus proses saat layanan dibuat dengan startService() dan diagram di sebelah kanan menunjukkan siklus proses saat layanan dibuat dengan bindService().

Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Meskipun gambar memisahkan layanan yang dibuat oleh startService() dari layanan yang dibuat oleh bindService(), perlu diingat bahwa layanan apa pun, terlepas dari cara memulainya, berpotensi memungkinkan klien untuk mengikat ke layanan tersebut. Layanan yang awalnya dimulai dengan onStartCommand() (oleh klien yang memanggil startService()) masih dapat menerima panggilan ke onBind() (saat klien memanggil bindService()).

Dengan menerapkan metode ini, Anda dapat memantau dua loop bertingkat dari siklus proses layanan:

Catatan: Meskipun layanan yang dimulai dihentikan oleh panggilan ke stopSelf() atau stopService(), tidak ada callback masing-masing untuk layanan (tidak ada callback onStop()). Kecuali jika layanan terikat ke klien, sistem akan menghapusnya saat layanan dihentikan—onDestroy() adalah satu-satunya callback yang diterima.

Untuk informasi selengkapnya tentang cara membuat layanan yang menyediakan binding, lihat dokumen Layanan Terikat, yang menyertakan informasi selengkapnya tentang metode callback onRebind() di bagian tentang Mengelola siklus proses layanan terikat.