Layanan

Service adalah sebuah komponen aplikasi yang bisa melakukan operasi yang berjalan lama di latar belakang dan tidak menyediakan antarmuka pengguna. Komponen aplikasi lain bisa memulai layanan dan komponen aplikasi tersebut akan terus berjalan di latar belakang walaupun pengguna beralih ke aplikasi lain. Selain itu, komponen bisa mengikat ke layanan untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan mungkin menangani transaksi jaringan, memutar musik, melakukan file I/O, atau berinteraksi dengan penyedia materi dari latar belakang.

Ada dua bentuk dasar layanan:

Dimulai
Layanan "sudah dimulai" bila komponen aplikasi (misalnya aktivitas) memulainya dengan memanggil startService(). Sesudah dimulai, layanan bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya telah dimusnahkan. Biasanya, layanan yang sudah dimulai akan melakukan operasi tunggal dan tidak mengembalikan hasil ke pemanggilnya. Misalnya, layanan bisa mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai, layanan seharusnya berhenti sendiri.
Terikat
Sebuah layanan akan "terikat" bila komponen aplikasi mengikatkan kepadanya dengan memanggil bindService(). Layanan terikat menawarkan antarmuka klien-server yang memungkinkan komponen berinteraksi dengan layanan tersebut, mengirim permintaan, mendapatkan hasil dan bahkan melakukannya pada sejumlah proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama ada komponen aplikasi lain yang terikat padanya. Sejumlah komponen bisa terikat pada layanan secara bersamaan, namun bila semuanya melepas ikatan, layanan tersebut akan dimusnahkan.

Walaupun dokumentasi ini secara umum membahas kedua jenis layanan secara terpisah, layanan Anda bisa menggunakan keduanya—layanan bisa dimulai (dijalankan terus-menerus) sekaligus memungkinkan pengikatan. Cukup mengimplementasikan dua metode callback: onStartCommand() untuk memungkinkan komponen memulainya dan onBind() untuk memungkinkan pengikatan.

Apakah aplikasi Anda sudah dimulai, terikat, atau keduanya, semua komponen aplikasi bisa menggunakan layanan (bahkan dari aplikasi terpisah), demikian pula semua komponen bisa menggunakan suatu aktivitas—dengan memulainya dengan Intent. Akan tetapi, Anda bisa mendeklarasikan layanan sebagai privat, pada file manifes, dan memblokir akses dari aplikasi lain. Hal ini dibahas selengkapnya di bagian tentang Mendeklarasikan layanan dalam manifes.

Perhatian: Layanan berjalan di thread utama proses yang menjadi host-nya—layanan tidak membuat thread-nya sendiri dan tidak berjalan pada proses terpisah (kecuali bila Anda tentukan demikian). Artinya, jika layanan Anda akan melakukan pekerjaan yang membutuhkan tenaga CPU besar atau operasi yang memblokir (seperti pemutaran MP3 atau jaringan), Anda perlu membuat thread baru dalam layanan untuk melakukan pekerjaan tersebut. Dengan menggunakan thread terpisah, Anda mengurangi risiko terjadinya kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan thread utama aplikasi bisa tetap dikhususkan pada interaksi pengguna dengan aktivitas Anda.

Dasar-Dasar

Untuk membuat layanan, Anda harus membuat subkelas Service (atau salah satu dari subkelasnya yang ada). Dalam implementasi, Anda perlu mengganti sebagian metode callback yang menangani aspek utama daur hidup layanan dan memberikan mekanisme bagi komponen untuk mengikat pada layanan, bila dibutuhkan. Metode callback terpenting yang perlu Anda ganti adalah:

onStartCommand()
Sistem akan memanggil metode ini bila komponen lain, misalnya aktivitas, meminta dimulainya layanan, dengan memanggil startService(). Setelah metode ini dieksekusi, layanan akan dimulai dan bisa berjalan di latar belakang terus-menerus. Jika mengimplementasikannya, Anda bertanggung jawab menghentikan layanan setelah pekerjaannya selesai, dengan memanggil stopSelf() atau stopService(). (Jika hanya ingin menyediakan pengikatan, Anda tidak perlu mengimplementasikan metode ini.)
onBind()
Sistem akan memanggil metode ini bila komponen lain ingin mengikat pada layanan (misalnya untuk melakukan PPK), dengan memanggil bindService(). Dalam mengimplementasikan metode ini, Anda harus menyediakan antarmuka yang digunakan klien untuk berkomunikasi dengan layanan, dengan mengembalikan IBinder. Anda harus selalu mengimplementasikan metode ini, namun jika tidak ingin mengizinkan pengikatan, Anda perlu mengembalikan null.
onCreate()
Sistem memanggil metode ini bila layanan dibuat untuk pertama kalinya, untuk melakukan prosedur penyiapan satu kali (sebelum memanggil onStartCommand() atau onBind()). Bila layanan sudah berjalan, metode ini tidak dipanggil.
onDestroy()
Sistem memanggil metode ini bila layanan tidak lagi digunakan dan sedang dimusnahkan. Layanan Anda perlu mengimplementasikannya untuk membersihkan sumber daya seperti thread, listener terdaftar, penerima, dll. Ini adalah panggilan terakhir yang diterima layanan.

Jika komponen memulai layanan dengan memanggil startService() (yang menyebabkan panggilan ke onStartCommand(), maka layanan akan terus berjalan hingga terhenti sendiri dengan stopSelf() atau bila komponen lain menghentikannya dengan memanggil stopService().

Jika komponen memanggil bindService() untuk membuat layanan (dan onStartCommand() tidak dipanggil), maka layanan hanya akan berjalan selama komponen terikat kepadanya. Setelah layanan dilepas ikatannya dari semua klien, sistem akan menghancurkannya.

Sistem Android akan menghentikan paksa layanan hanya bila memori tinggal sedikit dan sistem harus memulihkan sumber daya sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat pada suatu aktivitas yang mendapatkan fokus pengguna, layanan tersebut lebih kecil kemungkinannya untuk dimatikan, dan jika layanan dideklarasikan untuk berjalan di latar depan (akan dibahas kemudian), maka sudah hampir pasti ia tidak akan dimatikan. Sebaliknya, bila layanan sudah dimulai dan berjalan lama, maka sistem akan menurunkan posisinya dalam daftar tugas latar belakang seiring waktu dan layanan akan sangat rentan untuk dimatikan—bila layanan Anda dimulai, maka Anda harus mendesainnya agar bisa menangani mulai ulang oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai ulang begitu sumber daya kembali tersedia (tetapi ini juga bergantung pada nilai yang Anda kembalikan dari onStartCommand(), sebagaimana akan dibahas nanti). Untuk informasi selengkapnya tentang kapan sistem mungkin akan memusnahkan layanan, lihat dokumen Proses dan Threading.

Dalam bagian selanjutnya, Anda akan melihat bagaimana membuat masing-masing tipe layanan dan cara menggunakannya dari komponen aplikasi lain.

Mendeklarasikan layanan dalam manifes

Sebagaimana aktivitas (dan komponen lainnya), Anda harus mendeklarasikan semua layanan dalam file manifes aplikasi Anda.

Untuk mendeklarasikan layanan Anda, tambahkan sebuah elemen <service> sebagai anak elemen <application>. Misalnya:

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

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

Ada atribut lain yang bisa Anda sertakan dalam elemen <service> untuk mendefinisikan properti seperti izin yang diperlukan untuk memulai layanan dan proses tempat menjalankannya. Atribut android:name adalah satu-satunya yang diperlukan—atribut ini menetapkan nama kelas layanan. Setelah mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak kode karena dependensi terhadap maksud eksplisit untuk memulai atau mengikat layanan (bacalah entri blog berjudul Things That Cannot Change).

Untuk memastikan aplikasi Anda aman, selalu gunakan maksud eksplisit saat memulai atau mengikat Service Anda dan jangan mendeklarasikan filter maksud untuk layanan. Jika Anda perlu membiarkan ambiguitas tentang layanan mana yang dimulai, Anda bisa menyediakan filter maksud bagi layanan dan tidak menyertakan nama komponen dari Intent, namun Anda juga harus menyetel paket bagi maksud tersebut bersama setPackage(), yang menyediakan klarifikasi memadai bagi target layanan.

Anda juga bisa memastikan layanan tersedia hanya bagi aplikasi dengan menyertakan atribut android:exported dan menyetelnya ke "false". Hal ini efektif menghentikan aplikasi lain agar tidak memulai layanan Anda, bahkan saat menggunakan maksud eksplisit.

Membuat Layanan yang Sudah Dimulai

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

Bila layanan sudah dimulai, layanan tersebut memiliki daur hidup yang tidak bergantung pada komponen yang memulainya dan bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya dimusnahkan. Dengan sendirinya, layanan akan berhenti sendiri bila tugasnya selesai dengan memanggil stopSelf(), atau komponen lain bisa menghentikannya dengan memanggil stopService().

Komponen aplikasi seperti aktivitas bisa memulai layanan dengan memanggil startService() serta meneruskan Intent yang menetapkan layanan dan menyertakan data yang akan digunakan layanan. Layanan menerima Intent ini dalam metode onStartCommand().

Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas tersebut bisa memulai layanan pendamping dan mengiriminya data untuk disimpan dengan meneruskan maksud ke startService(). Layanan akan menerima maksud dalam onStartCommand(), menghubungkan ke Internet dan melakukan transaksi database. Bila transaksi selesai, layanan akan berhenti sendiri dan dimusnahkan.

Perhatian: Layanan berjalan dalam proses yang sama dengan aplikasi tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut, secara default. Jadi, bila layanan Anda melakukan operasi yang intensif atau operasi pemblokiran saat pengguna berinteraksi dengan aktivitas dari aplikasi yang sama, layanan akan memperlambat kinerja aktivitas. Agar tidak memengaruhi kinerja aplikasi, Anda harus memulai thread baru di dalam layanan.

Biasanya, ada dua kelas yang bisa Anda perluas untuk membuat layanan yang sudah dimulai:

Service
Ini adalah kelas dasar untuk semua layanan. Bila memperluas kelas ini, Anda perlu membuat thread baru sebagai tempat melaksanakan semua pekerjaan layanan tersebut, karena layanan menggunakan thread utama aplikasi Anda secara default, dan hal ini bisa memperlambat kinerja aktivitas yang dijalankan aplikasi Anda.
IntentService
Ini adalah subkelas Service yang menggunakan thread pekerja untuk menangani semua permintaan memulai, satu per satu. Ini adalah pilihan terbaik jika Anda tidak mengharuskan layanan menangani beberapa permintaan sekaligus. Anda cukup mengimplementasikan onHandleIntent(), yang menerima maksud untuk setiap permintaan memulai agar bisa melakukan pekerjaan latar belakang.

Bagian selanjutnya membahas cara mengimplementasikan layanan Anda menggunakan salah satu dari kelas-kelas ini.

Memperluas kelas IntentService

Mengingat kebanyakan layanan yang sudah dimulai tidak perlu menangani beberapa permintaan sekaligus (yang bisa berupa skenario multi-threading berbahaya), mungkin Anda sebaiknya mengimplementasikan layanan menggunakan kelas IntentService.

Berikut ini yang dilakukan IntentService:

  • Membuat thread pekerja default yang menjalankan semua maksud yang disampaikan ke onStartCommand() terpisah dari thread utama aplikasi Anda.
  • Membuat antrean pekerjaan yang meneruskan maksud satu per satu ke implementasi onHandleIntent(), sehingga Anda tidak perlu mengkhawatirkan multi-threading.
  • Menghentikan layanan setelah semua permintaan memulai telah ditangani, jadi Anda tidak perlu memanggil stopSelf().
  • Menyediakan implementasi default onBind() yang mengembalikan null.
  • Menyediakan implementasi default onStartCommand() yang mengirimkan maksud ke antrean pekerjaan kemudian ke implementasi onHandleIntent() Anda.

Semua ini akan menambahkan pada fakta bahwa Anda hanya perlu mengimplementasikan onHandleIntent() untuk melakukan pekerjaan yang disediakan oleh klien. (Akan tetapi, Anda juga perlu menyediakan konstruktor kecil bagi layanan.)

Berikut ini contoh implementasi IntentService:

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // 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();
      }
  }
}

Anda hanya memerlukan: konstruktor dan implementasi onHandleIntent().

Jika Anda memutuskan untuk menggantikan juga metode callback lain, seperti onCreate(), onStartCommand(), atau onDestroy(), pastikan memanggil implementasi super, sehingga IntentService bisa menangani hidup thread pekerja dengan baik.

Misalnya, onStartCommand() harus mengembalikan implementasi default (yang merupakan cara penyampaian maksud ke onHandleIntent()):

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

Selain onHandleIntent(), satu-satunya metode lain yang tidak mengharuskan Anda memanggil super kelas adalah onBind() (namun Anda hanya perlu mengimplementasikannya bila layanan mengizinkan pengikatan).

Dalam bagian berikutnya, Anda akan melihat bagaimana layanan serupa diimplementasikan saat memperluas kelas Service basis, yang membutuhkan kode lebih banyak lagi, namun mungkin cocok jika Anda perlu menangani beberapa permintaan memulai sekaligus.

Memperluas kelas Layanan

Seperti telah Anda lihat di bagian sebelumnya, menggunakan IntentService membuat implementasi layanan yang sudah dimulai jadi sangat sederhana. Namun, bila Anda mengharuskan layanan untuk melakukan multi-threading (sebagai ganti memproses permintaan memulai melalui antrean pekerjaan), maka Anda bisa memperluas kelas Service untuk menangani masing-masing maksud.

Sebagai perbandingan, kode contoh berikut ini adalah implementasi kelas Service yang melakukan pekerjaan yang persis sama dengan contoh di atas menggunakan IntentService. Artinya, untuk setiap permintaan memulai, kode tersebut akan menggunakan thread pekerja untuk melakukan tugas dan memproses permintaan satu per satu.

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // 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 will not 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
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @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 = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.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();
  }
}

Seperti yang bisa Anda lihat, ini membutuhkan lebih banyak pekerjaan daripada menggunakan IntentService.

Akan tetapi, karena Anda menangani sendiri setiap panggilan ke onStartCommand(), Anda bisa melakukan beberapa permintaan sekaligus. Itu bukan yang dilakukan contoh ini, namun jika itu yang diinginkan, Anda bisa membuat thread baru untuk setiap permintaan dan langsung menjalankannya (sebagai ganti menunggu permintaan sebelumnya selesai).

Perhatikan bahwa metode onStartCommand() harus mengembalikan integer. Integer tersebut merupakan nilai yang menjelaskan cara sistem melanjutkan layanan dalam kejadian yang dimatikan oleh sistem (sebagaimana dibahas di atas, implementasi default IntentService menangani hal ini untuk Anda, walaupun Anda bisa memodifikasinya). Nilai yang dikembalikan dari onStartCommand() harus berupa salah satu konstanta berikut ini:

START_NOT_STICKY
Jika sistem mematikan layanan setelah onStartCommand() dikembalikan, jangan membuat lagi layanan tersebut, kecuali jika ada maksud tertunda yang akan disampaikan. Inilah pilihan teraman untuk menghindari menjalankan layanan Anda bila tidak diperlukan dan bila aplikasi Anda bisa memulai ulang tugas yang belum selesai.
START_STICKY
Jika sistem mematikan layanan setelah onStartCommand() kembali, buat kembali layanan dan panggil onStartCommand(), namun jangan menyampaikan ulang maksud terakhir. Sebagai gantinya, sistem akan memanggil onStartCommand() dengan maksud nol, kecuali jika ada maksud tertunda untuk memulai layanan, dan dalam hal ini, maksud tersebut disampaikan. Ini cocok bagi pemutar media (atau layanan serupa) yang tidak mengeksekusi perintah, namun berjalan terus-menerus dan menunggu tugas.
START_REDELIVER_INTENT
Jika sistem mematikan layanan setelah onStartCommand() kembali, buat kembali layanan dan panggil onStartCommand() dengan maksud terakhir yang disampaikan ke layanan. Maksud yang tertunda akan disampaikan pada gilirannya. Ini cocok bagi layanan yang aktif melakukan tugas yang harus segera dilanjutkan, misalnya mengunduh file.

Untuk detail selengkapnya tentang nilai pengembalian ini, lihat dokumentasi acuan tertaut untuk setiap konstanta.

Memulai Layanan

Anda bisa memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan Intent (yang menetapkan layanan yang akan dimulai) ke startService(). Sistem Android akan memanggil metode onStartCommand() layanan dan meneruskan Intent padanya. (Jangan sekali-kali memanggil onStartCommand() secara langsung.)

Misalnya, aktivitas bisa memulai layanan contoh di bagian sebelumnya (HelloService) menggunakan maksud eksplisit dengan startService():

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

Metode startService() segera kembali dan sistem Android akan memanggil metode onStartCommand() layanan. Jika layanan belum berjalan, sistem terlebih dahulu memanggil onCreate(), kemudian memanggil onStartCommand().

Jika layanan juga tidak menyediakan pengikatan, maksud yang disampaikan dengan startService() adalah satu-satunya mode komunikasi antara komponen aplikasi dan layanan. Akan tetapi, jika Anda ingin agar layanan mengirimkan hasilnya kembali, maka klien yang memulai layanan bisa membuat PendingIntent untuk siaran (dengan getBroadcast()) dan menyampaikannya ke layanan dalam Intent yang memulai layanan. Layanan kemudian bisa menggunakan siaran untuk menyampaikan hasil.

Beberapa permintaan untuk memulai layanan menghasilkan beberapa panggilan pula ke onStartCommand() layanan. Akan tetapi, 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 memusnahkan layanan kecuali jika harus memulihkan memori sistem dan layanan terus berjalan setelah onStartCommand() kembali. Jadi, layanan tersebut harus berhenti sendiri dengan memanggil stopSelf() atau komponen lain bisa menghentikannya dengan memanggil stopService().

Setelah diminta untuk berhenti dengan stopSelf() atau stopService(), sistem akan memusnahkan layanan secepatnya.

Akan tetapi, bila layanan Anda menangani beberapa permintaan ke onStartCommand() sekaligus, Anda tidak boleh menghentikan layanan bila baru selesai memproses permintaan memulai, karena setelah itu mungkin Anda sudah menerima permintaan memulai yang baru (berhenti pada permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari masalah ini, Anda bisa menggunakan stopSelf(int) untuk memastikan bahwa permintaan Anda untuk menghentikan layanan selalu berdasarkan pada permintaan memulai terbaru. Artinya, bila Anda memanggil stopSelf(int), Anda akan meneruskan ID permintaan memulai (startId yang disampaikan ke onStartCommand()) yang terkait dengan permintaan berhenti Anda. Kemudian jika layanan menerima permintaan memulai baru sebelum Anda bisa memanggil stopSelf(int), maka ID tidak akan sesuai dan layanan tidak akan berhenti.

Perhatian: Aplikasi Anda perlu menghentikan layanannya bila selesai bekerja untuk menghindari pemborosan sumber daya sistem dan tenaga baterai. Jika perlu, komponen lain bisa menghentikan layanan secara eksplisit dengan memanggil stopService(). Bahkan jika Anda mengaktifkan pengikatan bagi layanan, Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke onStartCommand().

Untuk informasi selengkapnya tentang daur hidup layanan, lihat bagian di bawah ini tentang Mengelola Daur Hidup Layanan.

Membuat Layanan Terikat

Layanan terikat adalah layanan yang memungkinkan komponen aplikasi untuk mengikatnya dengan memanggil bindService() guna membuat koneksi yang berlangsung lama (dan umumnya tidak mengizinkan komponen untuk memulainya dengan memanggil startService()).

Anda sebaiknya membuat layanan terikat bila ingin berinteraksi dengan layanan dari aktivitas dan komponen lain dalam aplikasi Anda atau mengeskpos sebagian fungsionalitas aplikasi Anda ke ke aplikasi lain, melalui komunikasi antarproses (IPC).

Untuk membuat layanan terikat, Anda harus mengimplementasikan metode callback onBind() untuk mengembalikan IBinder yang mendefinisikan antarmuka bagi komunikasi dengan layanan. Komponen aplikasi lain kemudian bisa memanggil bindService() untuk mengambil antarmuka dan mulai memanggil metode pada layanan. Layanan hanya hidup untuk melayani komponen aplikasi yang terikat padanya, jadi bila tidak ada komponen yang terikat pada layanan, sistem akan memusnahkannya (Anda tidak perlu menghentikan layanan terikat seperti halnya bila layanan dimulai melalui onStartCommand()).

Untuk membuat layanan terikat, hal yang perlu dilakukan pertama kali adalah mendefinisikan antarmuka yang menetapkan cara klien berkomunikasi dengan layanan. Antarmuka antara layanan dan klien ini harus berupa implementasi IBinder dan yang harus dikembalikan layanan Anda dari metode callback onBind(). Setelah menerima IBinder, klien bisa mulai berinteraksi dengan layanan melalui antarmuka tersebut.

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

Ada beberapa cara untuk mengimplementasikan layanan terikat dan implementasinya lebih rumit daripada layanan yang sudah dimulai, jadi layanan terikat dibahas dalam dokumen terpisah tentang Layanan Terikat.

Mengirim Notifikasi ke Pengguna

Setelah berjalan, layanan bisa memberi tahu pengguna tentang suatu kejadian menggunakan Notifikasi Toast atau Notifikasi Bilah Status.

Notifikasi Toast adalah pesan yang muncul sebentar pada permukaan jendela saat ini kemudian menghilang, sementara notifikasi bilah status memberikan ikon di bilah status dengan pesan yang bisa dipilih oleh pengguna untuk melakukan suatu aksi (misalnya memulai suatu aktivitas).

Biasanya, notifikasi bilah status adalah teknik terbaik bila ada pekerjaan latar belakang yang sudah selesai (misalnya file selesai diunduh) dan pengguna kini bisa menggunakannya. Bila pengguna memilih notifikasi dari tampilan diperluas, notifikasi akan bisa memulai aktivitas (misalnya menampilkan file yang baru diunduh).

Lihat panduan developer Notifikasi Toast atau Notifikasi Bilah Status untuk informasi selengkapnya.

Menjalankan Layanan di Latar Depan

Layanan latar depan adalah layanan yang dianggap sebagai sesuatu yang diketahui secara aktif oleh pengguna, jadi bukan sesuatu yang akan dihapus oleh sistem bila memori menipis. Sebuah layanan latar depan harus memberikan notifikasi bagi bilah status, yang ditempatkan pada heading "Ongoing" yang artinya notifikasi tersebut tidak bisa diabaikan kecuali jika layanan dihentikan atau dihapus dari latar depan.

Misalnya, pemutar musik yang memutar musik dari suatu layanan harus diatur untuk berjalan di latar depan, karena pengguna mengetahui operasi tersebut secara eksplisit. Notifikasi di bilah status bisa menunjukkan lagu saat ini dan memungkinkan pengguna untuk menjalankan suatu aktivitas untuk berinteraksi dengan pemutar musik.

Untuk meminta agar layanan Anda berjalan di latar depan, panggil startForeground(). Metode ini memerlukan dua parameter: sebuah integer yang mengidentifikasi notifikasi secara unik dan Notification untuk bilah status. Misalnya:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

Perhatian: ID integer yang Anda berikan ke startForeground() tidak boleh 0.

Untuk membuang layanan dari latar depan, panggil stopForeground(). Metode ini memerlukan boolean, yang menunjukkan apakah notifikasi bilah status juga akan dihapus. Metode ini tidak menghentikan layanan. Akan tetapi, jika Anda menghentikan layanan saat masih berjalan di latar depan maka notifikasi juga akan dihapus.

Untuk informasi selengkapnya tentang notifikasi, lihat Membuat Notifikasi Bilah Status.

Mengelola Daur Hidup Layanan

Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, lebih penting lagi adalah memerhatikan dengan cermat bagaimana layanan Anda dibuat dan dimusnahkan, karena suatu layanan bisa berjalan di latar belakang tanpa disadari oleh pengguna.

Daur hidup layanan—dari saat dibuat hingga dimusnahkan—bisa mengikuti dua jalur berbeda:

  • Layanan yang sudah dimulai

    Layanan dibuat bila komponen lain memanggil startService(). Layanan kemudian berjalan terus-menerus dan harus berhenti sendiri dengan memanggil stopSelf(). Komponen lain juga bisa menghentikan layanan dengan memanggil stopService(). Bila layanan dihentikan, sistem akan menghancurkannya.

  • Layanan terikat

    Layanan dibuat bila komponen lain (klien) memanggil bindService(). Klien kemudian berkomunikasi dengan layanan melalui antarmuka IBinder. Klien bisa menutup koneksi dengan memanggil unbindService(). Sejumlah klien bisa mengikat pada layanan yang sama dan bila semuanya melepas ikatan, sistem akan memusnahkan layanan tersebut. (Layanan tidak perlu berhenti sendiri.)

Kedua jalur tersebut tidak benar-benar terpisah. Artinya, Anda bisa mengikat ke layanan yang sudah dimulai dengan startService(). Misalnya, layanan musik latar belakang bisa dimulai dengan memanggil startService() dengan Intent yang mengidentifikasi musik yang akan diputar. Kemudian, mungkin saat pengguna ingin mengontrol pemutar musik atau mendapatkan informasi tentang lagu saat ini, aktivitas bisa mengikat ke layanan dengan memanggil bindService(). Dalam kasus seperti ini, stopService() atau stopSelf() tidak menghentikan layanan hingga semua klien melepas ikatan.

Mengimplementasikan callback daur hidup

Seperti halnya aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan skeleton berikut memperagakan setiap metode daur hidup:

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // 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 mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @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 daur hidup aktivitas, Anda tidak perlu memanggil implementasi superkelas metode callback tersebut.

Gambar 2. Daur hidup layanan. Diagram di sebelah kiri menampilkan daur hidup bila layanan dibuat dengan startService() dan diagram di sebelah kanan menampilkan daur hidup bila layanan dibuat dengan bindService().

Dengan mengimplementasikan metode-metode ini, Anda bisa memantau dua loop tersarang (nested loop) daur hidup layanan:

Catatan: Meskipun layanan yang sudah dimulai dihentikan dengan panggilan ke stopSelf() atau stopService(), tidak ada callback tersendiri bagi layanan tersebut (tidak ada callback onStop()). Jadi, kecuali jika layanan terikat ke klien, sistem akan memusnahkannya bila layanan dihentikan—onDestroy() adalah satu-satunya callback yang diterima.

Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Walaupun gambar tersebut memisahkan layanan yang dibuat oleh startService() dari layanan yang dibuat oleh bindService(), ingatlah bahwa suatu layanan, bagaimana pun dimulainya, bisa memungkinkan klien mengikat padanya. Jadi, suatu layanan yang awalnya dimulai dengan onStartCommand() (oleh klien yang memanggil startService()) masih bisa menerima panggilan ke onBind() (bila klien memanggil bindService()).

Untuk informasi selengkapnya tentang membuat layanan yang menyediakan pengikatan, lihat dokumen Layanan Terikat, yang menyertakan informasi selengkapnya tentang metode callback onRebind() di bagian tentang Mengelola Daur Hidup Layanan Terikat.