Layanan
Materi:
- Pengantar
- Apa yang dimaksud dengan layanan?
- Mendeklarasikan layanan di manifes
- Layanan yang dimulai
- Layanan terikat
- Daur hidup layanan
- Layanan latar depan
- Layanan terjadwal
Dalam bab ini, Anda akan mempelajari tentang berbagai tipe layanan, cara menggunakannya, dan cara mengelola daur hidup layanan dalam aplikasi.
Apa yang dimaksud dengan layanan?
Layanan adalah komponen aplikasi yang menjalankan operasi yang berjalan lama, biasanya di latar belakang. Layanan tidak menyediakan antarmuka pengguna (UI). (Aktivitas, di sisi lain, menyediakan UI.)
Layanan bisa dimulai, diikat, atau keduanya:
- Layanan yang dimulai adalah layanan yang komponen aplikasinya memulai dengan memanggil
startService()
.Gunakan layanan yang dimulai untuk tugas yang berjalan di latar belakang guna menjalankan operasi yang berjalan lama. Selain itu, gunakan layanan yang dimulai untuk tugas yang menjalankan pekerjaan untuk proses jarak jauh. - Layanan terikat adalah layanan yang komponen aplikasinya diikat ke dirinya sendiri dengan memanggil
bindService()
.Gunakan layanan terikat untuk tugas yang berinteraksi dengan komponen aplikasi lain guna menjalankan komunikasi interproses (IPC). Misalnya, layanan terikat mungkin menangani transaksi jaringan, menjalankan I/O file, memutar musik, atau berinteraksi dengan penyedia materi.
Catatan: Layanan berjalan di thread utama dari proses hosting-nya—layanan tidak membuat thread sendiri dan tidak berjalan di proses terpisah kecuali jika Anda menetapkannya.
Jika layanan Anda akan melakukan pekerjaan yang banyak membutuhkan CPU atau operasi pemblokiran (seperti pemutaran MP3 atau jaringan), buat thread baru dalam layanan untuk melakukan pekerjaan itu. Dengan menggunakan thread terpisah, Anda akan mengurangi risiko kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan thread utama aplikasi bisa terus disediakan untuk interaksi pengguna dengan aktivitas Anda.
Untuk mengimplementasikan suatu jenis layanan dalam aplikasi Anda:
- Deklarasikan layanan di manifes.
- Buat kode implementasi, seperti yang dijelaskan dalam Layanan yang dimulai dan Layanan terikat, di bawah ini.
- Kelola daur hidup layanan.
Mendeklarasikan layanan di manifes
Sebagaimana dengan aktivitas dan komponen lainnya, Anda harus mendeklarasikan semua layanan dalam file manifes aplikasi. Untuk mendeklarasikan layanan, tambahkan elemen
sebagai anak dari elemen
. Misalnya:......
android:exported="false" />
Untuk memblokir akses ke layanan dari aplikasi lainnya, deklarasikan layanan sebagai privat. Caranya, setel atribut
android:exported
ke false
. Ini akan menghentikan aplikasi lain dari memulai layanan Anda, bahkan bila menggunakan maksud eksplisit.Layanan yang dimulai
Cara memulai layanan:
- Komponen aplikasi seperti aktivitas memanggil
startService()
dan meneruskannya diIntent
. Dalam hal iniIntent
menetapkan layanan dan menyertakan data yang akan digunakan oleh layanan. - Sistem akan memanggil metode
onCreate()
layanan dan callback lainnya yang sesuai di thread utama. Tergantung layanan untuk mengimplementasikan callback tersebut dengan perilaku yang sesuai, seperti membuat thread sekunder yang akan digunakan. - Sistem akan memanggil metode
onStartCommand()
layanan, dengan meneruskanIntent
yang disediakan oleh klien di langkah 1. (Klien dalam konteks ini adalah komponen aplikasi yang memanggil layanan.)
Setelah dimulai, layanan bisa berjalan di latar belakang tanpa dibatasi waktu, bahkan jika komponen yang memulainya telah dimusnahkan. Biasanya, layanan yang dimulai menjalankan operasi tunggal dan tidak mengembalikan hasil ke pemanggil. Misalnya, layanan dapat mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai, layanan harus berhenti sendiri dengan memanggil
stopSelf()
, atau komponen lain bisa menghentikannya dengan memanggil stopService()
.
Misalnya, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas akan memulai layanan pendamping dengan meneruskan
Intent
ke startService()
. Layanan menerima maksud di onStartCommand()
, menghubungkan ke Internet, dan menjalankan transaksi database. Bila transaksi selesai, layanan akan menggunakan stopSelf()
untuk menghentikan dirinya sendiri dan dimusnahkan. (Ini adalah contoh layanan yang ingin Anda jalankan di thread pekerja, sebagai ganti thread utama.)IntentService
Sebagian besar layanan yang dimulai tidak perlu menangani beberapa permintaan secara bersamaan, dan jika layanan melakukannya, maka akan mengakibatkan skenario multi-threading yang berbahaya. Karena itu, sebaiknya Anda mengimplementasikan layanan menggunakan kelas
IntentService
.IntentService
adalah subkelas yang berguna dari Service
:IntentService
secara otomatis menyediakan thread pekerja untuk menanganiIntent
.IntentService
menangani beberapa kode boilerplate yang diperlukan layanan umum (seperti memulai dan menghentikan layanan).IntentService
bisa membuat antrean pekerjaan yang meneruskan satu maksud untuk setiap kalinya ke implementasionHandleIntent()
, sehingga Anda tidak perlu mengkhawatirkan multi-threading.
Untuk mengimplementasikan
IntentService
:- Sediakan konstruktor kecil untuk layanan.
- Buat implementasi
onHandleIntent()
untuk melakukan pekerjaan yang disediakan klien.
Inilah 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. */* The IntentService calls this method from the default worker thread withpublic HelloIntentService() { super("HelloIntentService"); } /*** stops the service, as appropriate.* the intent that started the service. When this method returns, IntentService */ @Override protected void onHandleIntent(Intent intent) {Thread.sleep(5000);// Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { } catch (InterruptedException e) { // Restore interrupt status.}Thread.currentThread().interrupt(); }}
Layanan terikat
Layanan "terikat" bila komponen aplikasi mengikatnya dengan memanggil
bindService()
. Layanan terikat menawarkan antarmuka klien-server yang memungkinkan komponen berinteraksi dengan layanan, mengirim permintaan, dan mendapatkan hasil, kadang-kadang menggunakan komunikasi interproses (IPC) untuk mengirim dan menerima informasi di seluruh proses. Layanan terikat hanya berjalan selama komponen aplikasi terikat padanya. Beberapa komponen bisa diikat ke layanan sekaligus, namun bila semuanya telah dilepas, layanan akan dimusnahkan.
Layanan terikat umumnya tidak mengizinkan memulai komponen dengan memanggil
startService()
.Mengimplementasikan layanan terikat
Untuk mengimplementasikan layanan terikat, definisikan antarmuka yang menetapkan cara klien bisa berkomunikasi dengan layanan. Antarmuka ini, yang dikembalikan layanan Anda dari metode callback
onBind()
, harus berupa implementasi IBinder
.
Untuk mengambil antarmuka
IBinder
, komponen aplikasi klien memanggil bindService()
. Setelah klien menerima IBinder
, klien berinteraksi dengan layanan melalui antarmuka itu.
Ada sejumlah cara untuk mengimplementasikan layanan terikat, dan implementasi tersebut lebih rumit daripada layanan yang dimulai. Untuk detail selengkapnya tentang layanan terikat, lihat Layanan Terikat.
Mengikat ke layanan
Untuk mengikat ke layanan yang dideklarasikan di manifes dan diimplementasikan oleh komponen aplikasi, gunakan
bindService()
dengan Intent
eksplisit.
Perhatian: Jangan gunakan maksud implisit untuk mengikat ke layanan. Melakukannya adalah bahaya keamanan, karena Anda tidak bisa memastikan layanan yang akan merespons maksud tersebut, dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dengan Android 5.0 (API level 21), sistem membuat pengecualian jika Anda memanggil
bindService()
dengan Intent
implisit.Daur hidup layanan
Daur hidup layanan lebih sederhana daripada aktivitas. Akan tetapi, ini jauh lebih penting karena Anda memerhatikan dari dekat cara layanan dibuat dan dimusnahkan. Karena tidak memiliki UI, layanan bisa terus berjalan di latar belakang tanpa diketahui pengguna, bahkan jika pengguna beralih ke aplikasi lain. Ini menghabiskan sumber daya dan menguras baterai.
Seperti aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan untuk memantau perubahan keadaan layanan dan melakukan pekerjaan pada waktu yang sesuai. Layanan kerangka berikut memperagakan setiap metode daur hidup:
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killedIBinder mBinder; // interface for clients that bind@Overrideboolean mAllowRebind; // indicates whether onRebind should be used public void onCreate() {// The service is starting, due to a call to startService()// The service is being created } @Override public int onStartCommand(Intent intent, int flags, int startId) {// A client is binding to the service with bindService()return mStartMode; } @Override public IBinder onBind(Intent intent) { return mBinder; } @Overridepublic void onRebind(Intent intent) {public boolean onUnbind(Intent intent) { // All clients have unbound with unbindService() return mAllowRebind; } @Override// The service is no longer used and is being destroyed// A client is binding to the service with bindService(), // after onUnbind() has already been called } @Override public void onDestroy() { }}
Daur hidup layanan yang dimulai vs. layanan terikat
Layanan terikat hanya tersedia untuk menyajikan komponen aplikasi yang terikat padanya, sehingga bila tidak ada lagi komponen yang diikat ke layanan tersebut, sistem akan memusnahkannya. Layanan terikat tidak perlu dihentikan secara eksplisit seperti halnya layanan yang dimulai (menggunakan
stopService()
atau stopSelf()
).
Diagram di bawah ini menampilkan perbandingan antara daur hidup layanan yang dimulai dan terikat.
Layanan latar depan
Walaupun sebagian besar layanan berjalan di latar belakang, sebagian lagi ada yang berjalan di latar depan. Layanan latar depan adalah layanan yang diketahui pengguna, jadi ini bukan layanan yang bakal dimatikan sistem bila memori tinggal sedikit.
Misalnya, pemutar musik yang memutar musik dari layanan harus disetel untuk berjalan di latar depan, karena pengguna mengetahui operasinya. Notifikasi di bilah status dapat menunjukkan lagu saat ini dan memungkinkan pengguna meluncurkan aktivitas untuk berinteraksi dengan pemutar musik.
Untuk meminta agar layanan berjalan di latar depan, panggil
startForeground()
sebagai ganti startService()
. Metode ini menggunakan dua parameter: integer yang secara unik mengidentifikasi notifikasi dan Notification
untuk bilah status. Notifikasi ini sedang berlangsung, artinya tidak bisa ditutup. Notifikasi tetap berada di bilah status hingga layanan dihentikan atau dibuang dari latar depan.
Misalnya:
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this).setSmallIcon(R.drawable.notification_icon).setContentTitle("My notification")startForeground(ONGOING_NOTIFICATION_ID, mBuilder.build());.setContentText("Hello World!");
Catatan: 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 akan membuang notifikasi bilah status atau tidak. Metode ini tidak menghentikan layanan. Akan tetapi, jika Anda menghentikan layanan sewaktu masih berjalan di latar depan, maka notifikasi juga akan dibuang.Layanan terjadwal
Untuk API level 21 dan yang lebih tinggi, Anda bisa meluncurkan layanan menggunakan
JobScheduler
API. Untuk menggunakan JobScheduler
, Anda perlu mendaftarkan tugas dan menetapkan persyaratannya untuk jaringan dan pengaturan waktu. Sistem menjadwalkan tugas untuk dieksekusi di waktu yang tepat.