7.4: 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.
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 <service>
sebagai anak dari elemen <application>
. Misalnya:
<manifest ... >
...
<application ... >
<service android:name="ExampleService"
android:exported="false" />
...
</application>
</manifest>
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.
*/
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();
}
}
}
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.
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 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
}
}
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")
.setContentText("Hello World!");
startForeground(ONGOING_NOTIFICATION_ID, mBuilder.build());
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.
Antarmuka JobScheduler
menyediakan banyak metode untuk mendefinisikan ketentuan eksekusi layanan. Untuk detailnya, lihat JobScheduler reference
.