Service
adalah
komponen aplikasi yang dapat menjalankan
operasi yang berjalan lama di latar belakang. Aplikasi ini tidak menyediakan antarmuka pengguna. Setelah
dimulai, layanan dapat terus berjalan selama beberapa waktu, bahkan setelah pengguna beralih ke
aplikasi lain. Selain itu, komponen dapat diikat ke layanan untuk berinteraksi dengannya, dan bahkan melakukan
komunikasi antar-proses (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 dari proses hostingnya; layanan tidak membuat thread sendiri dan tidak berjalan dalam proses terpisah kecuali jika Anda menentukan lain. Anda harus menjalankan operasi pemblokiran apa pun pada thread terpisah dalam layanan untuk menghindari error Aplikasi Tidak Merespons (ANR).
Jenis Layanan
Inilah tiga tipe layanan yang berbeda:
- Latar depan
-
Layanan latar depan menjalankan 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 akan terus berjalan bahkan saat pengguna tidak berinteraksi dengan aplikasi.
Saat menggunakan layanan latar depan, Anda harus menampilkan notifikasi agar pengguna tahu secara aktif 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 terlihat secara langsung oleh
pengguna. Misalnya, jika aplikasi menggunakan layanan untuk memadatkan penyimpanannya,
aplikasi tersebut biasanya akan menjadi layanan latar belakang.
Catatan: Jika aplikasi Anda menargetkan API level 26 atau yang lebih tinggi, sistem akan menerapkan batasan untuk menjalankan layanan latar belakang saat aplikasi itu sendiri tidak berada di latar depan. Pada 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 mengikatnya dengan memanggil
bindService()
. Layanan terikat menawarkan antarmuka klien-server yang memungkinkan komponen untuk berinteraksi dengan layanan, mengirim permintaan, menerima hasil, dan bahkan melakukannya pada berbagai proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama komponen aplikasi lain terikat padanya. Beberapa komponen dapat terikat ke layanan sekaligus, tetapi jika semuanya terlepas, layanan akan dihancurkan.
Meskipun dokumentasi ini umumnya membahas layanan yang dimulai dan terikat secara terpisah,
layanan Anda dapat berfungsi dengan dua cara. Layanan ini dapat dimulai (untuk berjalan tanpa batas) dan juga memungkinkan
binding. Anda hanya tinggal mengimplementasikan beberapa metode callback: onStartCommand()
untuk memungkinkan 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
suatu aktivitas—dengan memulainya dengan Intent
. Akan tetapi, Anda dapat mendeklarasikan
layanan sebagai pribadi dalam file manifes dan memblokir akses dari aplikasi lain.
Hal ini dibahas selengkapnya di bagian tentang Mendeklarasikan layanan dalam
manifes.
Memilih antara layanan dan thread
Layanan hanyalah komponen yang dapat berjalan di latar belakang, meskipun pengguna tidak berinteraksi dengan aplikasi Anda. Jadi, sebaiknya buat layanan hanya jika Anda membutuhkannya.
Jika harus melakukan pekerjaan di luar thread utama, tetapi hanya saat pengguna berinteraksi
dengan aplikasi, sebaiknya buat thread baru dalam konteks komponen
aplikasi lain. Misalnya, jika Anda ingin memutar musik, tetapi hanya saat aktivitas sedang 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 informasi selengkapnya tentang
memindahkan eksekusi ke thread latar belakang.
Perlu diingat bahwa jika Anda menggunakan layanan, layanan tersebut tetap berjalan di thread utama aplikasi Anda 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-nya yang sudah ada. Dalam implementasinya, Anda harus mengganti beberapa metode callback yang
menangani aspek utama siklus proses layanan dan menyediakan mekanisme yang memungkinkan komponen
berikatan ke layanan, jika dirasa sesuai. Berikut adalah metode callback terpenting yang harus Anda
ganti:
onStartCommand()
- Sistem memanggil metode ini dengan memanggil
startService()
bila komponen lain (misalnya aktivitas) meminta layanan dimulai. Saat metode ini dijalankan, layanan akan dimulai dan dapat berjalan di latar belakang tanpa batas waktu. Jika menerapkannya, Anda bertanggung jawab untuk menghentikan layanan saat pekerjaannya selesai dengan memanggilstopSelf()
ataustopService()
. Jika hanya ingin menyediakan binding, Anda tidak perlu mengimplementasikan metode ini. onBind()
- Sistem memanggil metode ini dengan memanggil
bindService()
ketika komponen lain ingin terikat dengan layanan (seperti untuk menjalankan RPC). Dalam implementasi metode ini, Anda harus menyediakan antarmuka yang digunakan klien untuk berkomunikasi dengan layanan dengan menampilkanIBinder
. Anda harus selalu mengimplementasikan metode ini; tetapi, jika tidak ingin mengizinkan binding, Anda harus menampilkan null. onCreate()
- Sistem memanggil metode ini untuk menjalankan prosedur penyiapan satu kali saat layanan
pertama kali dibuat (sebelum memanggil
onStartCommand()
atauonBind()
). Jika layanan sudah berjalan, metode ini tidak akan dipanggil. onDestroy()
- Sistem memanggil metode ini saat layanan tidak lagi digunakan dan sedang dihancurkan. Layanan Anda harus mengimplementasikan tindakan ini untuk membersihkan resource 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 sampai menghentikannya sendiri dengan stopSelf()
atau
komponen lain menghentikannya dengan memanggil stopService()
.
Jika komponen memanggil
bindService()
untuk membuat layanan dan onStartCommand()
tidak dipanggil, layanan hanya akan berjalan
selama komponen terikat dengannya. Setelah layanan dilepas dari semua kliennya,
sistem akan menghapusnya.
Sistem Android akan menghentikan layanan hanya jika memori hampir penuh dan harus memulihkan resource
sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat dengan aktivitas yang memiliki fokus
pengguna, layanan tersebut cenderung tidak akan dimatikan; jika layanan dideklarasikan untuk berjalan di latar depan, layanan itu jarang dimatikan.
Jika layanan dimulai dan berjalan lama, sistem akan menurunkan posisinya
dalam daftar tugas latar belakang seiring waktu, dan layanan menjadi sangat rentan
dimatikan—jika layanan dimulai, Anda harus mendesainnya untuk menangani mulai ulang
oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai ulang begitu resource
tersedia, tetapi hal ini juga bergantung pada nilai yang Anda kembalikan dari onStartCommand()
. Untuk mengetahui informasi selengkapnya
tentang kapan sistem mungkin akan 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 lainnya.
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 Anda, tambahkan elemen <service>
sebagai turunan 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 dijalankan. Atribut android:name
adalah satu-satunya atribut yang diperlukan—atribut ini menentukan nama class layanan. Setelah
Anda memublikasikan aplikasi, jangan ubah nama ini untuk menghindari risiko merusak
kode karena ketergantungan pada intent eksplisit untuk memulai atau mengikat layanan (baca postingan blog, Things
That cannot Change).
Perhatian: Untuk memastikan aplikasi Anda aman, selalu gunakan
intent eksplisit saat memulai Service
dan jangan mendeklarasikan 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 mana
yang dimulai. Mulai dari Android 5.0 (API level 21), sistem akan menampilkan pengecualian jika Anda memanggil
bindService()
dengan intent implisit.
Anda dapat memastikan layanan tersedia hanya untuk aplikasi Anda dengan
menyertakan atribut android:exported
dan menyetelnya ke false
. Hal ini secara efektif mencegah aplikasi lain memulai
layanan Anda, bahkan saat menggunakan intent eksplisit.
Catatan:
Pengguna dapat melihat layanan yang sedang berjalan di perangkat mereka. Jika melihat
layanan yang tidak dikenali atau dipercaya, mereka dapat menghentikan layanan tersebut. Untuk menghindari penghentian layanan secara tidak sengaja oleh pengguna, Anda perlu menambahkan atribut android:description
ke elemen <service>
di manifes aplikasi Anda. Dalam deskripsi,
sediakan kalimat singkat yang menjelaskan fungsi layanan dan manfaat
yang diberikannya.
Membuat layanan yang sudah dimulai
Layanan yang dimulai adalah layanan yang dimulai komponen lain dengan memanggil startService()
, yang menghasilkan panggilan ke metode onStartCommand()
layanan.
Saat dimulai, layanan memiliki siklus proses yang terpisah dari
komponen yang memulainya. Layanan dapat berjalan di latar belakang tanpa batas waktu, meskipun
komponen yang memulainya telah dimusnahkan. 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 yang akan digunakan oleh layanan. Layanan menerima
Intent
ini dalam metode onStartCommand()
.
Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas
dapat memulai layanan pendamping dan mengirimkannya data untuk disimpan dengan meneruskan intent ke startService()
. Layanan akan menerima intent dalam onStartCommand()
, terhubung ke Internet, dan melakukan
transaksi database. Setelah transaksi selesai, layanan akan berhenti sendiri dan
dihancurkan.
Perhatian: Layanan berjalan dalam proses yang sama seperti aplikasi tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut secara default. Jika layanan Anda melakukan operasi yang intensif atau memblokir saat pengguna berinteraksi dengan aktivitas dari aplikasi yang sama, layanan akan memperlambat performa aktivitas. Agar tidak memengaruhi performa aplikasi, mulai thread baru di dalam layanan.
Class Service
adalah class dasar
untuk semua layanan. Saat memperluas class ini, penting untuk membuat thread baru tempat
layanan dapat menyelesaikan semua tugasnya; layanan ini menggunakan thread utama aplikasi Anda secara
default, yang dapat memperlambat performa aktivitas apa pun yang sedang berjalan aplikasi Anda.
Framework Android juga menyediakan subclass IntentService
dari Service
yang menggunakan
thread pekerja untuk menangani semua permintaan memulai, satu per satu. Menggunakan class ini tidak direkomendasikan untuk aplikasi baru karena class tersebut tidak akan berfungsi dengan baik dimulai dengan Android 8 Oreo, karena adanya pengantar Batas eksekusi latar belakang.
Selain itu, versi 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 sangat mempertimbangkan penggunaan WorkManager untuk sebagian besar kasus penggunaan. Lihat panduan pemrosesan latar belakang di Android untuk melihat apakah ada solusi yang sesuai dengan kebutuhan Anda.
Memperluas class Layanan
Anda dapat memperluas class Service
untuk menangani setiap intent yang masuk. Berikut adalah tampilan implementasi 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(); } }
Kode contoh ini menangani semua panggilan masuk di onStartCommand()
dan memposting pekerjaan ke Handler
yang berjalan di thread latar belakang. Fungsinya sama seperti IntentService
dan memproses semua permintaan secara berurutan, satu per satu.
Anda dapat mengubah kode untuk menjalankan pekerjaan di kumpulan thread, misalnya, jika Anda 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 mengakhirinya. Nilai yang ditampilkan
dari onStartCommand()
harus berupa salah satu konstanta
berikut:
START_NOT_STICKY
- Jika sistem menghentikan layanan setelah
onStartCommand()
ditampilkan, jangan membuat ulang layanan kecuali ada intent tertunda untuk ditayangkan. Ini adalah opsi teraman untuk menghindari menjalankan layanan Anda jika 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 panggilonStartCommand()
, tetapi jangan mengirim ulang intent terakhir. Sebagai gantinya, sistem akan memanggilonStartCommand()
dengan intent null kecuali jika ada intent yang tertunda untuk memulai layanan. Dalam hal ini, intent tersebut dikirimkan. Ini cocok untuk pemutar media (atau layanan serupa) yang tidak mengeksekusi perintah, tetapi berjalan tanpa batas waktu dan menunggu tugas. START_REDELIVER_INTENT
- Jika sistem menghentikan layanan setelah
onStartCommand()
ditampilkan, buat ulang layanan dan panggilonStartCommand()
dengan intent terakhir yang dikirimkan ke layanan. Intent yang tertunda akan disampaikan pada gilirannya. Ini cocok untuk layanan yang aktif melakukan tugas yang harus segera dilanjutkan, seperti mendownload file.
Untuk 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 yang akan dimulai.
Catatan: Jika aplikasi Anda menargetkan API level 26 atau versi lebih tinggi, sistem
akan memberlakukan pembatasan untuk 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 tersebut akan mempromosikan layanan itu sendiri
ke latar depan. Setelah dibuat, layanan harus memanggil
metode startForeground()
dalam
lima detik.
Misalnya, aktivitas dapat memulai layanan contoh di bagian sebelumnya (HelloService
) menggunakan intent eksplisit dengan startService()
, seperti yang ditampilkan di sini:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
Metode startService()
akan segera ditampilkan, dan
sistem Android 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 kembali hasilnya,
klien yang memulai layanan dapat membuat PendingIntent
untuk siaran
(dengan getBroadcast()
) dan mengirimkannya ke layanan
di Intent
yang memulai layanan. Layanan kemudian dapat menggunakan
siaran untuk menyampaikan 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 menghancurkan layanan
sesegera mungkin.
Jika layanan Anda menangani beberapa permintaan ke onStartCommand()
secara bersamaan, sebaiknya jangan menghentikan
layanan saat selesai memproses permintaan memulai, karena Anda mungkin telah menerima
permintaan memulai baru (berhenti di akhir permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari
masalah ini, Anda dapat menggunakan stopSelf(int)
untuk memastikan bahwa permintaan Anda untuk
menghentikan layanan selalu didasarkan pada permintaan memulai terbaru. Artinya, saat memanggil stopSelf(int)
, Anda meneruskan ID permintaan memulai (startId
yang dikirimkan ke onStartCommand()
) yang sesuai dengan
permintaan penghentian. Kemudian, jika layanan menerima permintaan memulai baru sebelum Anda dapat memanggil stopSelf(int)
, ID tersebut 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 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 mengikatnya dengan memanggil bindService()
untuk membuat koneksi yang bertahan lama.
Hal ini biasanya tidak mengizinkan komponen untuk memulai dengan memanggil startService()
.
Buat layanan terikat jika Anda ingin berinteraksi dengan layanan dari aktivitas dan komponen lain dalam aplikasi, atau untuk mengekspos beberapa fungsionalitas aplikasi ke aplikasi lain melalui komunikasi antarproses (IPC).
Untuk membuat layanan terikat, implementasikan 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 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 dengan cara yang sama seperti yang 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 berupa implementasi IBinder
dan yang harus ditampilkan oleh 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 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 mengimplementasikan layanan terikat, dan penerapannya lebih rumit daripada layanan yang dimulai. Karena alasan ini, diskusi layanan terikat muncul di 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 pada permukaan jendela saat ini hanya sesaat sebelum menghilang. Notifikasi status bar menyediakan ikon di status bar dengan pesan yang dapat dipilih pengguna untuk melakukan tindakan (seperti memulai aktivitas).
Biasanya, notifikasi status bar adalah teknik terbaik yang dapat digunakan saat pekerjaan latar belakang seperti download file selesai, dan pengguna kini dapat menindaklanjutinya. Bila pengguna memilih notifikasi dari tampilan yang diperluas, notifikasi dapat memulai aktivitas (seperti menampilkan file yang didownload).
Mengelola daur hidup layanan
Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, penting bagi Anda untuk memperhatikan baik-baik 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 jalur berikut:
- Layanan yang sudah dimulai
Layanan dibuat saat komponen lain memanggil
startService()
. Layanan kemudian berjalan tanpa batas waktu dan harus menghentikan dirinya sendiri dengan memanggilstopSelf()
. Komponen lain juga dapat menghentikan layanan dengan memanggilstopService()
. Bila layanan dihentikan, sistem akan memusnahkannya. - Layanan terikat
Layanan dibuat saat komponen lain (klien) memanggil
bindService()
. Klien kemudian berkomunikasi dengan layanan melalui antarmukaIBinder
. Klien dapat menutup koneksi dengan memanggilunbindService()
. Beberapa klien dapat mengikat ke layanan yang sama dan jika semuanya terlepas, sistem akan memusnahkan layanan. Layanan tidak perlu berhenti sendiri.
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()
menggunakan Intent
yang mengidentifikasi musik yang akan diputar. Nantinya,
mungkin saat pengguna ingin mengontrol pemutar atau mendapatkan informasi tentang
lagu saat ini, suatu aktivitas dapat mengikat ke layanan dengan memanggil bindService()
. Dalam kasus seperti ini, stopService()
atau stopSelf()
tidak benar-benar menghentikan layanan hingga semua klien melepas ikatan.
Mengimplementasikan callback daur hidup
Seperti aktivitas, layanan memiliki metode callback siklus proses yang bisa Anda implementasikan 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 funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // 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 voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Catatan: Tidak seperti metode callback siklus proses aktivitas, Anda tidak perlu memanggil implementasi superclass metode callback ini.
Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Meskipun gambar ini memisahkan
layanan yang dibuat oleh startService()
dari
layanan yang dibuat oleh bindService()
, perlu diingat
bahwa layanan apa pun, bagaimana pun dimulainya, berpotensi memungkinkan klien untuk mengikatnya.
Layanan yang awalnya dimulai dengan onStartCommand()
(oleh klien yang memanggil startService()
) masih dapat menerima panggilan ke onBind()
(saat klien memanggil bindService()
).
Dengan mengimplementasikan metode ini, Anda dapat memantau dua loop bertingkat dari siklus proses layanan:
- Seluruh masa aktif layanan terjadi antara waktu
onCreate()
dipanggil dan waktuonDestroy()
ditampilkan. Seperti aktivitas, layanan melakukan penyiapan awal dionCreate()
dan melepaskan semua resource yang tersisa dionDestroy()
. Misalnya, layanan pemutaran musik dapat membuat thread tempat musik diputar dalamonCreate()
, lalu dapat menghentikan thread dalamonDestroy()
.Catatan: Metode
onCreate()
danonDestroy()
dipanggil untuk semua layanan, baik yang dibuat olehstartService()
maupunbindService()
. - Masa aktif aktif layanan dimulai dengan panggilan ke
onStartCommand()
atauonBind()
. Setiap metode diberiIntent
yang diteruskan kestartService()
ataubindService()
.Jika layanan dimulai, masa aktif aktif berakhir pada saat yang sama dengan seluruh masa aktif berakhir (layanan masih aktif bahkan setelah
onStartCommand()
ditampilkan). Jika layanan terikat, masa aktif aktif akan berakhir saatonUnbind()
ditampilkan.
Catatan: Meskipun layanan yang dimulai dihentikan dengan panggilan ke
stopSelf()
atau stopService()
, tidak ada callback masing-masing untuk
layanan tersebut (tidak ada callback onStop()
). Kecuali layanan terikat ke klien,
sistem akan menghancurkannya saat layanan dihentikan—onDestroy()
adalah satu-satunya callback yang diterima.
Untuk mengetahui 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.