Bila komponen aplikasi dimulai dan tidak ada komponen aplikasi lain yang berjalan, sistem Android akan memulai proses Linux baru untuk aplikasi dengan satu thread eksekusi. Secara default, semua komponen aplikasi yang sama berjalan dalam proses dan thread yang sama (disebut thread "utama"). Jika komponen aplikasi dimulai dan sudah ada proses untuk aplikasi itu (karena komponen lain dari aplikasi itu sudah ada), maka komponen akan dimulai dalam proses itu dan menggunakan thread eksekusi yang sama. Akan tetapi, Anda bisa mengatur komponen berbeda di aplikasi agar berjalan di proses terpisah, dan Anda bisa membuat thread tambahan untuk setiap proses.
Dokumen ini membahas cara kerja proses dan thread di aplikasi Android.
Proses
Secara default, semua komponen aplikasi yang sama berjalan dalam proses yang sama dan kebanyakan aplikasi tidak boleh mengubah ini. Akan tetapi, jika Anda merasa perlu mengontrol proses milik komponen tertentu, Anda dapat melakukannya dalam file manifes.
Entri manifes untuk setiap tipe elemen komponen—
<activity>
, <service>
, <receiver>
, dan <provider>
—mendukung atribut android:process
yang bisa menetapkan dalam
proses mana komponen harus dijalankan. Anda bisa mengatur atribut ini
agar setiap komponen
berjalan dalam prosesnya sendiri atau agar beberapa komponen menggunakan
proses yang sama sementara yang lainnya tidak. Anda juga bisa menyetel
android:process
agar komponen aplikasi yang berbeda berjalan dalam proses yang sama
—sepanjang aplikasi menggunakan ID pengguna Linux yang sama dan ditandatangani
dengan sertifikat yang sama.Elemen
<application>
juga mendukung atribut android:process
, untuk menyetel
nilai default yang berlaku bagi semua komponen.Android bisa memutuskan untuk mematikan proses pada waktu tertentu, bila memori tinggal sedikit dan diperlukan oleh proses lain yang lebih mendesak untuk melayani pengguna. Komponen aplikasi yang berjalan dalam proses yang dimatikan maka sebagai konsekuensinya juga akan dimusnahkan. Proses dimulai kembali untuk komponen itu bila ada lagi pekerjaan untuk mereka lakukan.
Saat memutuskan proses yang akan dimatikan, sistem Android akan mempertimbangkan kepentingan relatifnya bagi pengguna. Misalnya, sistem lebih mudah menghentikan proses yang menjadi host aktivitas yang tidak lagi terlihat di layar, dibandingkan dengan proses yang menjadi host aktivitas yang terlihat. Karena itu, keputusan untuk menghentikan proses bergantung pada status komponen yang berjalan dalam proses tersebut. Aturan yang digunakan untuk menentukan proses yang akan dihentikan dibahas di bawah ini.
Daur hidup proses
Sistem Android mencoba mempertahankan proses aplikasi selama mungkin, namun pada akhirnya perlu membuang proses lama untuk mengambil kembali memori bagi proses baru atau yang lebih penting. Untuk menentukan proses yang akan dipertahankan dan yang harus dimatikan, sistem menempatkan setiap proses ke dalam "hierarki prioritas" berdasarkan komponen yang berjalan dalam proses dan status komponen tersebut. Proses yang memiliki prioritas terendah akan dimatikan terlebih dahulu, kemudian yang terendah berikutnya, dan seterusnya, jika perlu untuk memulihkan sumber daya sistem.Ada lima tingkatan dalam hierarki prioritas. Daftar berikut berisi beberapa tipe proses berdasarkan urutan prioritas (proses pertama adalah yang terpenting dan dimatikan terakhir):
- Proses latar depan
Proses yang diperlukan untuk aktivitas yang sedang dilakukan pengguna. Proses
dianggap berada di latar depan jika salah satu kondisi berikut terpenuhi:
- Proses menjadi host
Activity
yang berinteraksi dengan pengguna dengan (Activity
dengan metodeonResume()
telah dipanggil). - Proses menjadi host
Service
yang terikat dengan aktivitas yang sedang berinteraksi dengan pengguna. - Proses menjadi host
Service
yang berjalan "di latar depan"— layanan telah memanggilstartForeground()
. - Proses menjadi host
Service
yang menjalankan salah satu callback daur hidupnya (onCreate()
,onStart()
, atauonDestroy()
). - Proses menjadi host
BroadcastReceiver
yang menjalankan metodeonReceive()
.
- Proses menjadi host
- Proses yang terlihat
Proses yang tidak memiliki komponen latar depan, namun masih bisa
memengaruhi apa yang dilihat pengguna di layar. Proses dianggap terlihat jika salah satu kondisi
berikut terpenuhi:
- Proses ini menjadi host
Activity
yang tidak berada di latar depan, namun masih terlihat oleh pengguna (metodeonPause()
telah dipanggil). Ini bisa terjadi, misalnya, jika aktivitas latar depan memulai dialog, sehingga aktivitas sebelumnya terlihat berada di belakangnya. - Proses menjadi host
Service
yang terikat dengan aktivitas yang terlihat (atau latar depan)
- Proses ini menjadi host
- Proses layanan
Proses yang menjalankan layanan yang telah dimulai dengan metode
startService()
dan tidak termasuk dalam salah satu dari dua kategori yang lebih tinggi. Walaupun proses pelayanan tidak langsung terkait dengan semua yang dilihat oleh pengguna, proses ini umumnya melakukan hal-hal yang dipedulikan pengguna (seperti memutar musik di latar belakang atau mengunduh data di jaringan), jadi sistem membuat proses tetap berjalan kecuali memori tidak cukup untuk mempertahankannya bersama semua proses latar depan dan proses yang terlihat.
- Proses latar belakang
Proses yang menampung aktivitas yang saat ini tidak terlihat oleh pengguna (metode
onStop()
aktivitas telah dipanggil). Proses ini tidak memiliki dampak langsung pada pengalaman pengguna, dan sistem bisa menghentikannya kapan saja untuk memperoleh kembali memori bagi proses latar depan, proses yang terlihat, atau proses layanan. Biasanya ada banyak proses latar belakang yang berjalan, sehingga disimpan dalam daftar LRU (least recently used atau paling sedikit digunakan) untuk memastikan bahwa proses dengan aktivitas yang paling baru terlihat oleh pengguna sebagai yang terakhir untuk dimatikan. Jika aktivitas mengimplementasikan metode daur hidupnya dengan benar, dan menyimpan statusnya saat ini, menghentikan prosesnya tidak akan memiliki efek yang terlihat pada pengalaman pengguna, karena ketika pengguna kembali ke aktivitas, aktivitas itu memulihkan semua statusnya yang terlihat. Lihat dokumen Aktivitas untuk mendapatkan informasi tentang menyimpan dan memulihkan status.
- Proses kosong
Sebuah proses yang tidak berisi komponen aplikasi aktif apa pun. Alasan satu-satunya mempertahankan proses
seperti ini tetap hidup adalah untuk keperluan caching, meningkatkan waktu mulai (startup) bila
nanti komponen perlu dijalankan di dalamnya. Sistem sering menghentikan proses ini untuk menyeimbangkan sumber
daya sistem secara keseluruhan antara proses cache dan cache kernel yang mendasarinya.
Selain itu, peringkat proses dapat meningkat karena adanya proses lain yang bergantung padanya —proses yang melayani proses lain tidak bisa diperingkat lebih rendah daripada proses yang sedang dilayaninya. Misalnya, jika penyedia materi dalam proses A melayani klien dalam proses B, atau jika layanan dalam proses A terikat dengan komponen dalam proses B, proses A selalu dipertimbangkan sebagai paling rendah prioritasnya dibandingkan dengan proses B.
Karena proses yang menjalankan layanan diperingkat lebih tinggi daripada aktivitas latar belakang, aktivitas yang memulai operasi yang berjalan lama mungkin lebih baik memulai layanan untuk operasi itu, daripada hanya membuat thread pekerja—khususnya jika operasi mungkin akan berlangsung lebih lama daripada aktivitas. Misalnya, aktivitas yang mengunggah gambar ke situs web harus memulai layanan untuk mengunggah sehingga unggahan bisa terus berjalan di latar belakang meskipun pengguna meninggalkan aktivitas tersebut. Menggunakan layanan akan memastikan operasi paling tidak memiliki prioritas "proses layanan", apa pun yang terjadi pada aktivitas. Ini menjadi alasan yang sama yang membuat penerima siaran harus menjalankan layanan daripada hanya menempatkan operasi yang menghabiskan waktu di thread.
Thread
Bila aplikasi diluncurkan, sistem akan membuat thread eksekusi untuk aplikasi tersebut, yang diberi nama, "main". Thread ini sangat penting karena bertugas mengirim kejadian ke widget antarmuka pengguna yang sesuai, termasuk kejadian menggambar. Ini juga merupakan thread yang membuat aplikasi berinteraksi dengan komponen dari toolkit Android UI (komponen dari paket
android.widget
dan android.view
). Karena itu, thread 'main' juga terkadang
disebut thread UI.Sistem ini tidak membuat thread terpisah untuk setiap instance komponen. Semua komponen yang berjalan di proses yang sama akan dibuat instance-nya dalam thread UI, dan sistem akan memanggil setiap komponen yang dikirim dari thread itu. Akibatnya, metode yang merespons callback sistem (seperti
onKeyDown()
untuk melaporkan tindakan pengguna atau metode callback daur hidup)
selalu berjalan di thread UI proses.Misalnya saat pengguna menyentuh tombol pada layar, thread UI aplikasi akan mengirim kejadian sentuh ke widget, yang selanjutnya menetapkan status ditekan dan mengeposkan permintaan yang tidak divalidasi ke antrean kejadian. Thread UI akan menghapus antrean permintaan dan memberi tahu widget bahwa widget harus menggambar dirinya sendiri.
Saat aplikasi melakukan pekerjaan intensif sebagai respons terhadap interaksi pengguna, model thread tunggal ini bisa menghasilkan kinerja yang buruk kecuali jika Anda mengimplementasikan aplikasi dengan benar. Khususnya jika semua terjadi di thread UI, melakukan operasi yang panjang seperti akses ke jaringan atau kueri database akan memblokir seluruh UI. Bila thread diblokir, tidak ada kejadian yang bisa dikirim, termasuk kejadian menggambar. Dari sudut pandang pengguna, aplikasi seperti hang atau mogok. Lebih buruk lagi, jika thread UI diblokir selama lebih dari beberapa detik (saat ini sekitar 5 detik) pengguna akan ditampilkan dialog "aplikasi tidak merespons" (ANR) yang populer karena reputasi buruknya. Pengguna nanti bisa memutuskan untuk keluar dari aplikasi dan mencopot pemasangan aplikasi jika mereka tidak suka.
Selain itu, toolkit Android UI bukan thread-safe. Jadi, Anda tidak harus memanipulasi UI dari thread pekerja—Anda harus melakukan semua manipulasi pada antarmuka pengguna dari thread UI. Sehingga hanya ada dua aturan untuk model thread tunggal Android:
- Jangan memblokir thread UI
- Jangan mengakses toolkit Android UI dari luar thread UI
Thread pekerja
Karena model thread tunggal yang dijelaskan di atas, Anda dilarang memblokir thread UI demi daya respons UI aplikasi. Jika memiliki operasi untuk dijalankan yang tidak seketika, Anda harus memastikan untuk melakukannya di thread terpisah (thread "latar belakang" atau thread "pekerja").Misalnya, berikut ini beberapa kode untuk listener klik yang mengunduh gambar dari thread terpisah dan menampilkannya dalam
ImageView
:public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork("http://example.com/image.png"); mImageView.setImageBitmap(b); } }).start(); }Awalnya hal ini tampak bekerja dengan baik, karena menciptakan thread baru untuk menangani operasi jaringan. Akan tetapi, hal tersebut melanggar aturan kedua model thread tunggal: jangan mengakses toolkit Android UI dari luar thread UI—contoh ini memodifikasi
ImageView
dari thread pekerja sebagai ganti thread UI. Ini bisa
mengakibatkan perilaku yang tidak terdefinisi dan tidak diharapkan, yang
bisa menyulitkan dan menghabiskan waktu untuk melacaknya.Untuk memperbaiki masalah ini, Android menawarkan beberapa cara untuk mengakses thread UI dari thread lainnya. Berikut ini daftar metode yang bisa membantu:
Misalnya, Anda bisa memperbaiki kode di atas dengan menggunakan metode
View.post(Runnable)
:public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); }Kini implementasi ini thread-safe: operasi jaringan dilakukan terpisah dari thread sementara
ImageView
dimanipulasi dari thread UI.Akan tetapi, karena operasi semakin kompleks, jenis kode seperti ini bisa semakin rumit dan sulit dipertahankan. Untuk menangani interaksi yang lebih kompleks dengan thread pekerja, Anda bisa mempertimbangkan penggunaan
Handler
di thread pekerja, untuk memproses pesan yang dikirim dari
thread UI. Mungkin solusi terbaiknya adalah memperpanjang kelas AsyncTask
,
yang akan menyederhanakan eksekusi tugas-tugas thread pekerja yang perlu berinteraksi dengan UI.Menggunakan AsyncTask
DenganAsyncTask
, Anda bisa melakukan pekerjaan asinkron pada antarmuka
pengguna. AsyncTask memblokir operasi di thread pekerja kemudian mempublikasikan hasilnya
di thread UI, tanpa mengharuskan Anda untuk menangani sendiri thread dan/atau penangan sendiri.Untuk menggunakannya, Anda harus menjadikan
AsyncTask
sebagai subkelas dan mengimplementasikan metode callback doInBackground()
yang berjalan di pool
thread latar belakang. Untuk memperbarui UI, Anda harus mengimplementasikan onPostExecute()
, yang mengirim hasil dari doInBackground()
dan berjalan di thread UI, jadi Anda bisa
memperbarui UI dengan aman. Kemudian Anda bisa menjalankan tugas dengan memanggil execute()
dari thread UI.Misalnya, Anda bisa mengimplementasikan contoh sebelumnya menggunakan
AsyncTask
dengan cara ini:public void onClick(View v) { new DownloadImageTask().execute("http://example.com/image.png"); } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { /** The system calls this to perform work in a worker thread and * delivers it the parameters given to AsyncTask.execute() */ protected Bitmap doInBackground(String... urls) { return loadImageFromNetwork(urls[0]); } /** The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Bitmap result) { mImageView.setImageBitmap(result); } }Kini UI aman dan kode jadi lebih sederhana, karena memisahkan pekerjaan ke dalam bagian-bagian yang harus dilakukan pada thread pekerja dan thread UI.
Anda harus membaca acuan
AsyncTask
untuk memahami sepenuhnya
cara menggunakan kelas ini, namun berikut ini ringkasan singkat cara kerjanya:- Anda bisa menetapkan tipe parameter, nilai kemajuan, dan nilai akhir tugas, dengan menggunakan generik
- Metode
doInBackground()
berjalan secara otomatis pada thread pekerja onPreExecute()
,onPostExecute()
, danonProgressUpdate()
semuanya dipanggil pada thread UI- Nilai yang dikembalikan oleh
doInBackground()
akan dikirim keonPostExecute()
- Anda bisa memanggil
publishProgress()
kapan saja didoInBackground()
untuk mengeksekusionProgressUpdate()
pada thread UI - Anda bisa membatalkan tugas ini kapan saja, dari thread mana saja
Perhatian: Masalah lain yang mungkin Anda temui saat menggunakan
thread pekerja adalah mulai ulang tak terduga dalam aktivitas karena perubahan konfigurasi waktu proses
(seperti saat pengguna mengubah orientasi layar), yang bisa memusnahkan thread pekerja. Untuk
melihat cara mempertahankan tugas selama mulai ulang ini dan cara membatalkan
tugas dengan benar saat aktivitas dimusnahkan, lihat kode sumber untuk aplikasi contoh Shelves.
Metode thread-safe
Dalam beberapa situasi, metode yang Anda implementasikan bisa dipanggil dari lebih dari satu thread, dan karena itu harus ditulis agar menjadi thread-safe.Ini terutama terjadi untuk metode yang bisa dipanggil dari jauh —seperti metode dalam layanan terikat. Bila sebuah panggilan pada metode yang dijalankan dalam
IBinder
berasal dari proses yang sama di mana
IBinder
berjalan, metode ini akan dieksekusi di thread pemanggil.
Akan tetapi, bila panggilan berasal proses lain, metode akan dieksekusi dalam thread yang dipilih dari
kumpulan (pool) thread yang dipertahankan sistem dalam proses yang sama seperti IBinder
(tidak dieksekusi dalam thread UI proses). Misalnya, karena metode
onBind()
layanan akan dipanggil dari thread UI
proses layanan, metode yang diimplementasikan dalam objek yang dikembalikan onBind()
(misalnya, subkelas yang mengimplementasikan metode PPK) akan dipanggil dari thread
di pool. Karena layanan bisa memiliki lebih dari satu klien, maka lebih dari satu pool thread bisa melibatkan
metode IBinder
yang sama sekaligus. Metode IBinder
karenanya harus diimplementasikan sebagai thread-safe.Penyedia materi juga bisa menerima permintaan data yang berasal dalam proses lain. Meskipun kelas
ContentResolver
dan ContentProvider
menyembunyikan detail cara mengelola komunikasi antarproses, metode ContentProvider
yang merespons permintaan itu—metode query()
, insert()
, delete()
, update()
, dan getType()
—dipanggil dari pool thread pada proses penyedia materi, bukan thread UI
untuk proses tersebut. Mengingat metode ini bisa dipanggil dari thread mana pun
sekaligus, metode-metode ini juga harus diimplementasikan sebagai thread-safe. Komunikasi Antarproses
Android menawarkan mekanisme komunikasi antarproses (IPC) menggunakan panggilan prosedur jauh (PPK), yang mana metode ini dipanggil oleh aktivitas atau komponen aplikasi lain, namun dieksekusi dari jauh (di proses lain), bersama hasil yang dikembalikan ke pemanggil. Ini mengharuskan penguraian panggilan metode dan datanya ke tingkat yang bisa dipahami sistem operasi, mentransmisikannya dari proses lokal dan ruang alamat untuk proses jauh dan ruang proses, kemudian merakit kembali dan menetapkannya kembali di sana. Nilai-nilai yang dikembalikan akan ditransmisikan dalam arah berlawanan. Android menyediakan semua kode untuk melakukan transaksi IPC ini, sehingga Anda bisa fokus pada pendefinisian dan implementasi antarmuka pemrograman PPK.
Tidak ada komentar:
Posting Komentar