BAB III DASAR PEMROGRAMAN ANDROID 3.1 Latar Belakang Perkembangan aplikasi Android saat ini berkembang dengan pesat. Bermacam-macam aplikasi Android gratis ataupun bayar dapat kita install di handphone (smartphone) berbasis sistem operasi Android. Banyaknya kebutuhan aplikasi-aplikasi berbasis Android di masa sekarang dan masa yang akan datang membuka peluang yang sangat menjanjikan bagi siapa saja yang mau untuk menjadi pembuat atau pengembang aplikasi Android. Namun kebanyakan dari pemilik smartphone saat ini hanya sebagai pengguna aplikasinya saja. Sudah saatnya sekarang ini kita Putra Putri Bangsa Indonesia membuat atau mengembangkan aplikasi Android dan menunjuk ke pada dunia bahwa kita mampu bersaing secara global, salah satunya dengan membuat atau mengembangkan aplikasi Android, atau minimal aplikasinya bisa digunakan sendiri. Oleh karena itu, tutorial ini dibuat untuk khusunya bagi siapa saja yang ingin menjadi pembuat atau pengembang aplikasi Android dan umumnya bagi yang ingin menambah wawasan tentang Android. Untuk memulai pemrograman Android, pengetahuan dan pemahaman akan dasar dari pemrograman Android tersebut sangatlah penting. Pemahaman yang dimaksud seperti memahami mekanisme kerja komponen dalam sistem operasi Android dan bagaimana menggunakan komponen secara efektif dalam membuat aplikasi Android tersebut. Tanpa pengetahuan dan pemahaman tersebut kita ibarat kapal yang berlayar tanpa membawa peta. Pada Tutorial ini akan membahas tentang struktur, mekanisme dan contoh program dari setiap komponen yang ada di pemrograman Android. Materi yang akan dibahasa diantaranya pengenalan dasar widget view (Text Control, Button, Check Box, Radio Button,Lis t View, Grid View,Spinner, Date and Time), Layout, Adapter, Menu, Dialog, dan Animasi. 3.2 Tujuan Setelah mempelajari tutorial ini, pembaca diharapkan dapat: a. Memahami dasar pemrograman Android. b. Mengetahui dan memahami komponen yang ada pada aplikasi Android. Dasar Pemrograman Android Page 61 c. Mengetahui dan memahami mekanisme kerja komponen dalam sistem operasi Android. d. Memahami dan dapat menggunakan Widget View, Layout, Adapter, Menu, Dialog dan Animasi. e. Dapat menggunakan komponen secara efektif dalam membuat aplikasi di Android. f. Dapat membuat program sederhana dengan memanfaatkan komponen yang ada pada aplikasi Android. 3.3 Dasar Pemrograman Android Aplikasi Android ditulis dengan menggunakan bahasa pemrograman Java. Kode Java dikompilasi beserta dengan data dan file sumber yang dibutuhkan oleh aplikasi yang digabungkan oleh tool aapt ke dalam paket Android, dan hasilnya berupa file archive berekstensi .apk. File inilah yang di distribusikan atau diunduh pengguna dan menginstalnya ke dalam perangkat mobile. Semua kode yang ada di dalam sebuah file berekstensi .apk dianggap sebagai sebuah aplikasi. Dalam banyak hal, setiap aplikasi Android hidup di dalam dunianya sendiri: a. Secara default, setiap aplikasi berjalan pada proses Linuxnya masing-masing. Android memulai prosesnya ketika kode yang ada di dalam aplikasi akan dieksekusi, dan akan mengakhirinya ketika proses itu tidak lagi diperlukan(system resources akan digunakan oleh aplikasi lain). b. Setiap proses mempunyai virtual machine(VM) masing-masing, sehingga kode aplikasi akan dipisahkan dari aplikasi yang lainnya. c. Secara default, setiap aplikasi diberikan sebuah user ID Linux yang unik. Aturan penggunaan telah ditentukan sedemikian rupa sehingga hanya pengguna yang berhak saja yang dapat mengakses dan menggunakan aplikasi tersebut walaupun ada beberapa cara untuk mengekspor sebuah aplikasi ke dalam aplikasi lainnya. User ID yang sama juga dapat digunakan oleh dua buah aplikasi sehingga aplikasi tersebut dapat melihat file yang ada di kelolah oleh kedua aplikasi tersebut. User ID dapat mengatur dua aplikasi, sehingga kedua aplikasi tersebut dapat saling berbagi file dan virtual machine untuk menghemat system resources. Dasar Pemrograman Android Page 62 3.4 Komponen Aplikasi Fitur utama dari Android adalah sebuah aplikasi dapat menggunakan elemen dari aplikasi lainnya (apabila diizinkan). Contohnya, jika aplikasi ditugaskan untuk menampilkan daftar gambar yang dapat bergulir, maka aplikasi yang lain dapat menggunakannya untuk menampilkan di dalam aplikasi tersebut. Fungsi yang sama dapat dipanggil di dalam dua aplikasi tanpa harus membuatnya lagi. Aplikasi Android tidak mempunyai single entry point di dalamnya (contohnya, tidak ada fungsi main()). Namun, Android mempunyai komponen penting yang dapat di instantiate dan dijalankan oleh sistem apabila dibutuhkan. Ada empat macam komponen, yaitu: a. Activities Sebuah activity menyajikan sebuah user interface visual yang berfokus pada kegiatan dari user. Sebuah aplikasi dapat terdiri dari satu atau beberapa activity. Ragam dan banyaknya activity tersebut tergantung pada aplikasi dan perancangannya. Umumnya, sebuah activity ditugaskan sebagai activity pertama yang akan tampil ketika aplikasi dijalankan, kemudian dilanjutkan oleh activity berikutnya. Contohnya, sebuah aplikasi dapat menyajikan daftar menu item atau menampilkan gambar beserta keterangan yang dipilih oleh user. Sebuah aplikasi pengiriman teks bisa mempunyai sebuah activity yang menampilkan daftar kontak untuk mengirim pesan, activity kedua adalah menulis pesan ke kontak yang telah dipilih, dan activity yang lain adalah menampilkan pesan lama atau mengubah pengaturan pesan. Walaupun activity tersebut bekerja bersama pada sebuah user interface, namun setiap activity tidak saling bergantung satu sama lain. Setiap activity diimplementasikan sebagai turunan (subclass) dari class utama. b. Services. Servis adalah sebuah komponen aplikasi yang dapat melakukan operasi panjang yang berjalan di background dan tidak menyediakan sebuah tampilan. Komponen aplikasi yang lain dapat memulai sebuah servis dan terus berjalan di background meskipun pengguna berpindah ke aplikasi lain. Sebagai tambahan, sebuah komponen dapat mengikat ke sebuah services dan bahkan melakukan komunikasi antar proses (interprocess communication/IPC). Sebagai contoh, sebuah services dapata menangani traksaksi jaringan, memutar musik, Dasar Pemrograman Android Page 63 melakukan file I/O, atau berinteraksi dengan sebuah content provider semuanya berjalan di background. Pada dasarnya sebuah services memiliki dua bentuk : a. Started Sebuah services “started” ketika sebuah komponen aplikasi (misalnya activity) memulainya dengan memanggil startService(). Sekali dimulai, sebuah services dapat berjalan di background tanpa batas, bahkan jika komponen yang telah berjalan di hancurkan. Biasanya, sebuah services yang telah berjalan akan melakukan operasi tunggal dan tidak mengembalihan sebuah hasil ke pemanggil. Sebagai contoh, mengunduh atau mengunggah sebuah file melalui jaringan. Ketika operasi berjalan, services harus berhenti dengan sendirinya. b. Bound Sebuah services “bound” ketika sebuah komponen aplikasi mengikat kepadanya dengan memanggil bindService(). Sebuah bound services menawarkan sebuah antarmuka klien-server yang memungkinkan komponen untuk berinteraksi dengan services, mengirimkan permintaan, memperoleh hasil dan bahkan melakukan seluruh proses dengan interprocess communication(IPC). Sebuah bound services hanya berjalan selama komponen aplikasi lain terikat kepadanya. Banyak komponen dapat terikat kepada services sekali, tetapi ketika seluruhnya melepaskan ikatan, services akan dihancurkan. Sebuah services dapat melakukan keduanya, services dapat dimulai dan juga memungkinkan mengikat, dengan mengimplementasikan sepasang method callback: onStartCommand() untuk memungkin komponen memulai services dan onBind() untuk memungkinkan mengikatnya. Terlepas dari apakah aplikasi dijalankan, terikat, atau keduanya, komponen aplikasi dapat menggunakan services ini (bahkan dari aplikasi terpisah), dengan cara yang sama setiap komponen dapat menggunakan suatu activity dengan memulainya menggunakan sebuah Intent. Services dapat dideklarasikan sebagai private di file manifest, dan membatasi akses dari aplikasi lain. Bagian ini akan dibahas lebih pada sesi “Mendeklarasikan Services di Manifest” Dasar Pemrograman Android Page 64 The Basic Sebuah services dapat dibuat dengan membuat sebuah subclass dari Service. Pada pengimplementasian, dibutuhkan beberapa method callback yang menangani aspek kunci dari siklus hidup services dan menyediakan sebuah mekanisme untuk komponen mengikat ke services ini, jika sesuai. Method callback yang paling penting untuk di override adalah : a. onStartCommand() Sistem akan memanggil method ini ketika komponen lain seperti sebuah activity, meminta service untuk dimulai dengan memannggil startService(). Sekali method ini dieksekusi, services akan dimulai dan dapat berjalan di background tanpa batas. Jika ini diterapkan, maka services harus di hentikan ketika tugasnya telah selesai dengan memanggil stopSelf() atau stopService(). b. onBind() Sistem memanggil method ini ketika komponen lain ingin mengikat dengan services (misalnya melakukan RPC), dengan memanggil bindService(). Pada saat Anda menerapkan method ini, Anda harus menyediakan sebuah antarmuka yang digunakan klien untuk berkomunikasi dengan services, dengan mengembalikan Ibinder. Anda harus selalu menerapkan method ini, tapi jika Anda tidak mengizinkan binding, makan Anda harus mengembalikan null. c. onCreate() Sistem memanggil method ini ketika services pertama kali dibuat, untuk melakukan satu kali prosedur setup (sebelum memanggil onStartCommand() atau onBind() yang lain). Jika services telah berjalan, method ini tidak akan dipanggil. d. onDestroy() Sistem memanggil method ini ketika services tidak lagi digunakan dan akan dihancurkan. Services Anda harus menerapkan ini untuk membersihkan berbagai resouces seperti threads, registered listener, receivers, dan lain-lain. Method ini merupakan panggilan terakhir yang diterima oleh services. Jika sebuah komponen di mulai dengan memanggil startService() (yang merupakan hasil pemanggilan onStartCommand()), kemudian services akan tetap berjalan hingga berhenti Dasar Pemrograman Android Page 65 dengan sendirinya dengan stopSelf() atau komponen lain menghentikannya dengan memanggil stopService(). Jika sebuah komponen memanggil bindService() untuk menciptakan services (dan onStartCommand() tidak dipanggil), services akan berjalan hanya selama komponen terikat kepadanya. Sekali layanan tidak terikat dengan semua klien, sistem akan menghancurkannya. Sistem Android akan force-stop sebuah services hanya jika memory rendah dan harus memulihkan sumber daya sistem untuk activity yang menjadi fokus pengguna. Jika services terikat dengan sebuah activity yang menjadi fokus pengguna, services tersebut memiliki kemungkinan kecil untuk di kill dan jika services di deklarasikan untuk berjalan di depan latar, maka services tersevut hampir tidak akan di kill. Declaring a Service in Manifest Seperti halnya activity, semua services yang digunakan pada aplikasi harus dideklarasian di file manifest. Untuk mendeklarasikan services, tambahkan elemen <service> sebagai anak dari elemen <application>. Dapat dilihat contoh koding di bawah ini. <manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest> Ada atribut lain yang dapat Anda masukkan ke dalam elemen <service> untuk menentukan properti, seperti permissions untuk memulai services dan menentukan proses yang harus di jalankan oleh services. Atribut android:name merupakan atribut yang dibutuhkan, atribut ini menentukan nama dari services. Ketika Anda mempublish aplikasi, Anda tidak diperkenankan untuk mengubah nama ini, karena jika diubah akan menyebabkan merusak beberapa fungsi yang digunakan oleh intents yang mengacu kepada services tersebut. Sama seperti activity, sebuah services dapat mendefinisikan intent filters yang mengizinkan componen lain untuk meminta services menggunakan implicit intents. Dengan mendeklarasikan intent filter, komponen dari berbagai aplikasi yang terinstal di handset pengguna dapat menjalankan services Anda jika services Dasar Pemrograman Android Page 66 tersebut mendeklarasikan sebuah intent filter yang sesuai dengan intent dari aplikasi lain yang dilewatkan ke startService(). Creating a Started Service Sebuah started services merupakan salah satu komponen starts dengan memanggil startService(), menghasilkan sebuah panggilan ke method onStartCommand(). Ketika sebuah services di jalankan, services tersebut memiliki siklus hidup yang independen dan dapat berjalan di belakang layar tanpa batas, bahkan jika komponen yang berjalan mulai hancur. Dengan demikian, services harus berhenti sendiri ketika tugasnya dilakukan dengan memanggil stopSelf(), atau komponen lain dapat menghentikannya dengan memanggil stopServices(). Sebuah komponen aplikasi seperti sebuah activity dapat memullai services dengan memanggil startService() dan melewatkan sebuah Intent yang menentukan services dan termasuk data yang digunakan oleh services. Services menerima Intent ini dalam method onStartComand(). Misalnya, suatu kegiatan perlu menyimpan data ke database online. Activity dapat menjalankan sebuah services pendamping dan mengirimkan data yang akan disimpan dengan melewatkan intent() onStartCommand(), untuk startService(). Services menerima intent di menghubungkan ke internet dan melakukan transaksi database. Setelah transaksi dilakukan, services berhenti sendiri dan akan dihancurkan. Ada dua class yang dapat di extends untuk membuat sebuah services. a. Services Merupakan class daras untuk semua services. Ketika mengextends class ini, penting utnuk membuat thread baru sebagai tempat kerja services, karena services ini menggunakan thread utama dari aplikasi yang dibuat, secara default dapat memperlambat kinerja dari setiap aktivitas aplikasi yang berjalan. b. IntentServices Merupakan subclass dari Services yang menggunakan thread untuk menangani semua permintaan awal satu per satu. Merupakan pilihan terbaik jika services yang ditangani tidak memerlukan beberapa request secara bersamaan. Yang harus dilakukan adalah mengimplementasikan onHandleIntent(), yang menerima intent untuk setiap request sehingga dapat melakukan background work. Dasar Pemrograman Android Page 67 Sesi berikut menjelaskan bagaimana menimplementasikan services menggunakan salah satu dari class tersebut. Extending the IntentService Class Karena sebagian started services tidak perlu menangani berbagai permintaan secara simulatan (yang dapat menjadi sebuah skenario multi-threading yang berbahaya), sebaiknya mengimplement services menggunakan class IntentService. IntentServices melakukan hal-hal berikut: a. Membuat sebuah worker thread yang mengeksekusi seluruh intent yang dikirimkan ke onStartComand() terpisah dari thread utama aplikasi. b. Membuat sebuah work queue yang melewatkan sebuah intent pada suatu waktu ke penerapan onHandleIntent(), sehingga Anda tidak perlu mengkhawatirkan multithreading. c. Menghentikan services setelah semua request ditangani, sehingga tidak perlu memanggil stopSelf(). d. Menyediakan implementasi standar dari onBind() yang mengembalikan null. e. Menyediakan asebuah implementasi standar dari onStartCommand() yang mengirimkan intent ke antrian kerja dan kemudian ke implementasi onHandleIntent(). Yang dibutuhkan adalah mengimplementasikan onHandleIntent() untuk melakukan pekerjaan yang disediakan oleh klien. Contoh: 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 Dasar Pemrograman Android Page 68 * 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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } } Jika akan meng override method callback, seperti onCreate(), onStartCommand() atau onDestroy(), pastikan untuk memanggil implementasi super, sehingga IntentServices dapat menangani worker thread. Sebagai contoh, onStartCommand() harus mengembalikan implementasi standar (bagaimana intent mengirim 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(), method yang tidak dibutuhkan untuk memanggil super class adalah onBind() (tapi dibutuhkan jika services mengizinkan binding). Extending the Service Class Penggunaan IntentService membuat implementasi sebuah started service sangat sederhana. Jika services melakukan multi-threading (daripada memproses start request melalui sebuah antrian kerja), dapat dilakukan dengan meng extenda class Service untuk menangani setiap intent. Sebagai perbandingan, contoh kode berikut adalah sebuah implementasi dari kelas Service yang melakukan pekerjaan yang sama dengan contoh diatas yang menggunakan IntentServices. Untuk setiap start request, menggunakan sebuah worker thread untuk melakukan pekerjaan dan hanya memproses satu request pada satu waktu. Dasar Pemrograman Android Page 69 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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // 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 Dasar Pemrograman Android Page 70 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(); } } Perlu diperhatikan bahwa method onStartCommand() harus mengembalikan integer. Integer adalah sebuah nilai yang menjelaskan bagaimana sistem harus melanjutkan services pada event yang dimatikan oleh system. Nilai kembalian dari onStartCommand() harus satu dari konstanta berikut: START NOT STICKY Jika sistem mematikan services setelah onStartCommand() dikembalikan, tidak membuat ulang services, kecuali ada intent yang harus dikirim. Merupakan opsi yang aman untuk menghindari menjalankan services jika tidak dibutuhkan dan ketika aplikasi dapat dengan mudah restart pekerjaan yang belum selesai. START STICKY Jika sistem mematikan services setelah onStartCommand() dikembalikan, membuat ulang services dan memanggil onStartCommand(), tetapi tidak mengirimkan kembali intent terakhir. Melainkan, sistem memanggil onStartCommand() dengan sebuah null intent, meskipun terdapat intent yang tertunda untuk memulai services, pada kasus intent tersebut dikirimkan. Cocok Dasar Pemrograman Android Page 71 digunakan untuk media players (atau services yang serupa) yang tidak mengeksekusi perintah, tetapi berjalan tanpa batas dan menunggu sebuah pekerjaan. START REDELIVER INTENT Jika sistem mematikan services setelah onStartCommand() dikembalikan, membuat ulang services dan memanggil onStartCommand() dengan intent terakhir yang telah dikrimkan ke services. Semua intent yang tertunda dikirimkan berurutan. Cocok digunakan untuk sevis yang aktif melakukan sebuah pekerjaan dan harus segera di resume seperti mengunduh sebuah file. Untuk lebih jelasnya mengenai nilai kembalian ini, lihat dokumentasi untuk setiap konstanta. Starting a Service Sebuah services dari activity atau komponen aplikasi lain dapat dijalankan dengan melewatkan sebuah intent ke startService(). Sistem Android memanggil method onStartCommand() dan melewatkan intent. (Jangan memanggil onStartCommand() secara langsung). Sebagai contoh, sebuah activity dapat memulai contoh services pada sesi sebelumnya (HelloService) menggunakan sebuah explisit intent dengan startService(): Intent intent = new Intent(this, HelloService.class); startService(intent); Method startService() dikembalikan segera dan sistem Android memanggil method onStartCommand(). Jika services ini belum berjalan, sistem pertama memanggil onCreate(), kemudian memanggil onStartCommand(). Jika services juga tidak menyediakan binding, intent dikirimkan dengan startService() merupakan satu-satunya mode komunikasi antara komponen aplikasi dan services. Akan tetapi jika anda ingin services mengirimkan nilai kembali, kemudian klien yang dimulai servicesnya dapat membuat sebuah PendingIntent untuk broadcast (dengan getBroadcast()) dan mengirimkan ke services dalam Intent yang servicesnya dimulai. Services dapat menggunakan broadcast untuk mengirimkan hasil. Berbagai request untuk memulai services menghasilkan berbagai panggilan yang saling berkaitan ke onStartCommand(). Akan tetapi, hanya satu permintaan untuk menghentikan services yang dibutuhkan untuk menghentikannya (stopSelf() atau stopService()). Dasar Pemrograman Android Page 72 Stopping a Service Sebuah started services harus mengelola siklus hidupnya. Sistem tidak menghentikan atau menghancurkan services kecuali recover memori sistem dan services diteruskan setelah onStartCommand() stopSelf() atau dikembalikan. Jadi, services ini harus berhenti sendiri dengan memanggil komponen lain dapat menghentikannya dengan memanggil stopService(). Ketika ada permintaan untuk berhenti dengan stopSelf() atau stopService(), sistem akan langsung menghancurkan services. Akan tetapi, jika services menangani beberapa permintaan untuk onStartCommand() secara bersamaan, maka services tersebut tidak harus dihentikan setelah selesai memproses request awal, karena bisa saja ada request baru yang diterima (berhenti pada akhir request pertama akan menghentikan request selanjutnya). Untuk menghindari masalah ini, bisa digunakan dengan perintah stopSelf(int) untuk memastikan bahwa request untuk menghentikan services selalu berdasarkan start request terbaru. Artinya, ketika stopSelf(int) dipanggil, anda akan onStartCommand()) ke melewatkan ID dari start request (startId dikirimkan ke stop request yang sesuai. Kemudian jika services menerima start request baru sebelum memanggil stopSelf(int), kemudian ID tidak cocok dan services tidak akan dihentikan. Creating a Bound Service Sebuah bound services adalah salah satu services yang memungkinkan komponen aplikasi untuk mengikatnya dengan memangil bindServic() dalam rangka membuat sebuah longstanding connection (dan secara umum tidak mengizinkan komponen untuk memanggilnya dengan memanggil startService()). Untuk membuat sebuah bound services akan dijelaskan pada bagian Bound Service. Sending Notification to the User Setelah berjalan, services dapat mengirimkan pemberitahuan kepada user menggunakan Toast atau Status Bar. Pemberitahuan berupa toast adalah pesan yang muncul pada permukaan jendela yang aktif yang sesaat kemudian menghilang, sementara status bar menyediakan sebuah ikon di status bar dengan sebuah pesan dimana pengguna dapat menentukan tindakan yang akan dilakukan (seperti memulai suatu activity). Dasar Pemrograman Android Page 73 Biasanya pemberitahuan menggunakan status bar merupakan teknik terbaik ketika beberapa background work telah selesai (seperti download file telah selesai) dan pengguna dapat melakukan tindakan padanya. Ketika pengguna memilih pemberitahuan dari tampilan, pemberitahuan dapat memulai sebuah activity (seperti melihat file yang telah didownload) Panduan membuat pemberitahuan berupa Toast ataupun Status Bar akan dibahas tersendiri. Running a Service in the Foreground Sebuah foreground services adalah services yang dianggap sebagai sesuatu yang menjadi perhatian bagi pengguna untuk dimatikan ketika memori low. Sebuah foreground services harus menyediakan sebuah pemberitahuan untuk status bar, yang ditempatkan dibawah judul “Ongoing”, yang berarti bahwa notifikasi tidak dapat dihentikan kecuali services dihentikan atau di hilangkan dari foreground. Sebagai contoh, sebuah music player yang memainkan music dari sebuah services harus di atur untuk berjalan di foreground, karena pengguna secara eksplisit memperhatikan operasi ini. Pemberitahuan pada status bar menunjukkan lagu yang sedang diputar dan pengguna untuk memulai sebuah activity yang berinteraksi dengan music player. Untuk request services berjalan di foreground, panggil startForeground(). Method ini membutuhkan dua parameter: integer yang unik untuk mengidentifikasi pemberitahuan dan Notification untuk status bar. Contoh : 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, notification); Untuk menghilangkan services dari foreground, panggil stopForeground(). Method ini mengambil sebuah nilai boolean, yang mengindikasi untuk menghilangkan pemberitahuan status bar. Method ini tidak menghentikan services. Akan tetapi, jika services di hentikan ketika sedang berjalan di foreground, kemudian pemberitahuan akan dihancurkan. Dasar Pemrograman Android Page 74 Managing the Lifecycle of a Service Siklus hidup dari sebuah services, lebih sederhana dibandingkan dengan siklus hidup activity. Akan tetapi, hal ini bahkan lebih penting memperhatikan bagaimana services diciptakan dan dihancurkan, karena services dapat berjalan di background tanpa diperhatikan oleh user. Siklus hidup services dimulai dari diciptakan dan dihancurkan, dapat mengikuti dua jalur : a. Started service Sebuah services diciptakan ketika komponen lain memanggil startService(). Services kemudian berjalan tanpa batas dan harus berhenti sendiri dengan memanggil stopSelf(). Komponen lain juga menghentikan services dengan memanggil stopService(). Ketika services berhenti, sistem akan menghancurkannya. b. Bound service Services diciptakan ketika komponen lain (sebuah klien) memanggil bindService(). Klien kemudian berkomunikasi dengan services melalui antarmukan Ibinder . Klien dapat menutup koneksi dengan memanggil unbindService(). Banyak klien dapat terikat pada services yang sama, dan ketika mereka semua dilepaskan, sistem akan menghancurkan services tersebut. Kedua jalur ini, tidak sepenuhnya terpisah. Komponen dapat mengikat ke services yang telah berjalan dengan startService(). Sebagai contoh, sebuah services backgroun music dapat dimulai dengan memanggil startService() dengan sebuah intent yang mengidentifiasi musik untuk di putar. Kemudian, mungkin ketika pengguna ingin melakukan kontrol atas pemutar musik atau mendapatkan informasi tentang lagu saat ini, suatu activity dapat mengikat ke services dengan memanggil bindService(). Dalam kasus seperti ini, stopService() atau stopSelf() tidak benar-benar menghentikan layanan tersebut hingga semua klien tidak terikat. Implementing the lifecycle callbacks Seperti activity, services memiliki method callback yang dapat diimplementasikan untuk memonitor perubahan pada satus services dan melakukan pekerjaan pada waktu yang sesuai. Berikut adalah demonstrasi dari skeleton services untuk setiap siklus hidup method: public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for kliens that bind boolean mAllowRebind; // indicates whether onRebind should be used @Override public void onCreate() { // The service is being created Dasar Pemrograman Android Page 75 } @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 klien is binding to the service with bindService() return mBinder; } @Override public boolean onUnbind(Intent intent) { // All kliens have unbound with unbindService() return mAllowRebind; } @Override public void onRebind(Intent intent) { // A klien 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 } } Dengan mengimplementasikan method ini, dan dapat memonitor dua perulangan bersarang dari siklus hidup services: a. Entire lifetime dari services terjadi antara waktu pemanggilan onCreate() dan waktu pengembalian onReturns(). Seperti sebuah activity, sebuah services melakukan inisial setup pada onCreate() dan melepaskan semua sumber daya yang tersisa pada onDestroy(). Contoh: sebuah services pemutar musik dapat membuat thread dimana music akan di mainkan di onCreate(), kemudian menghentikan thread pada onDestroy(). Method onCreate() dan onDestroy() di panggil untuk seluruh services, baik services yang dibuat oleh startService() maupun bindService(). b. Active lifetime dari services dimulai dengan memanggil onStartCommand() atau onBind(). Setiap method ditangani oleh Intent yang melewatkan masing-masing startService() atau bindService(). Dasar Pemrograman Android Page 76 Jika services dimulai, active lifetime diakhiri pada waktu yang sama dengan entire lifetime (services ini akan tetap aktif bahakan setelah onStartCommand dikembalikan). Jika services terikat, active lifetime akan diakhiri ketika onUnbind() dikembalikan. Gambar diatas mengilustrasikan method calback untuk sebuah services. Meskipun gambar diatas services terpisah yang dibuat oleh startService() dan oleh bindService(), perlu diingat bahwa services apapun, tidak peduli bagaimana dimulai, berpotensi dapat mengizinkan klien untuk terikat pada services tersebut. Sehingga sebuah services yang dimulai dengan onStartCommand() (dengan klien memanggil startService()) dapat menerima sebuah panggilan untuk onBind() (ketika klien memanggil bindService()). c. Content providers Sebuah content provider mengatur sharing aplikasi sehingga dapat digunakan oleh aplikasi lainnya. Data tersebut dapat disimpan di file system, dalam sebuah database SQLite, di Dasar Pemrograman Android Page 77 website, atau dalam ContentProvider bentuk untuk lain. Content provider mengimplementasikan akan meng-extend serangkaian method class yang memungkinkan aplikasi lain untuk mengambil dan menyimpan data sesuai dengan yang dikendalikannya. Namun, aplikasi tidak memanggil method ini secara langsung melainkan dengan menggunakan object class Content Resolver dan memanggil method di dalamnya. Contoh content provider Android yaitu pengaturan informasi kontak user dan aplikasi NotePad untuk menyimpan catatan. Kebanyakan aplikasi memiliki data yang hanya akan diakses oleh aplikasi tersebut. Bahkan oleh OS Android, aplikasi lain tidak dapat membaca maupun menulis ke data pada aplikasi tersebut. Akan tetapi, pada beberapa aplikasi membutuhkan data yang biasa untuk dibagi ke aplikasi lain. Aplikasi lain diharapkan dapat menulis dan membaca pada data yang dibuat oleh aplikasi tersebut. Contoh data ini adalah data informasi Kontak. Content Provider merupakan penyimpanan dan pengambil data serta membuatnya dapat diakses oleh semua aplikasi. Ketika diinginkan pembuatan data public maka terdapat dua pilihan yang dapat digunakan yaitu membuat Content Provider sendiri atau menambahkan data ke Content Provider yang ada. Seluruh Content Provider mengimplementasikan interface bersama untuk melakukan query ke provider dan mendapatkan kembaliannya serta untuk menambahkan, mengubah dan menghapus data. Content Provider yang telah tersedia pada sistem Android dapat dilihat pada tabel xx. Content Provider Data Browser Browser bookmark, browser history CallLog Panggilan tidak terjawab, rincian panggilan Contacs Contact details MediaStore File media seperti audio, video dan gambar Settings Pengaturan dan preferensi perangkat Dasar Pemrograman Android Page 78 ContentResolver Kelas ContentResolver menyediakan akses aplikasi ke content. Kelas ini merupakan interface yang biasa digunakan oleh klien untuk mengakses content secara tidak langsung. ContentResolver didapatkan dengan memanggil method getContentResolver() dari dalam Activity atau komponen aplikasi lainnya. ContentResolver cr = getContentResolver(); Setelah didapat objek ContentResolver maka dapat digunakan method-method dari objek tersebut untuk berinteraksi dengan Content Provider yang diinginkan. Ketika query dimulai, maka Android akan mengidentifikasi Content Provider target query, memastikannya ada dan berjalan. Sistem akan memulai seluruh objek ContentProvider tetapi dapat berkomunikasi dengan objek ContentResolver beberapa aplikasi yang berbeda dan proses. Interaksi antara proses ditangani oleh kelas ContentResolver dan ContentProvider. Query ke Content Provider Sama seperti bab sebelumnya, Query untuk Content Provider akan mengembalikan objek cursor. Untuk melakukan query yang dibutuhkan: URL mengidentifikasi provider, nama dari kolom yang diambil, dan jenis data yang akan diambil. Dalam melakukan query dapat menggunakan method ContentRevolver.query() atau Activity.manageQuery(). Kedua method ini akan mengembalikan objek cursor. Walau demikian, managedQuery() akan mengakibatkan activity untuk mengelola life cycle dari cursor. Pengaturan ini akan menangani ketika activity pause, dan meng-query Activity.startManagingCursor() kembali ketika activity restart. Method digunakan untuk memulai pengelolaan dari objek cursor. Apabila activity dihentikan secara otomatis akan memanggil deactive() pada cursor yang diberikan. Jika Activity restart, maka akan memanggil requery dan ketika activity dihancurkan maka semua cursor yang ada akan ditutup secara otomatis. Argumen pertama query() atau menagedQuery() adalah URI dari provider yaitu CONTENT_URI konstan yang mengidentifikasi ContentProvider tertentu dan kumpulan data. Untuk membatasi query hanya satu record, dengan menambahkan nilai_id untuk URI dengan menempatkan string yang cocok dengan ID sebagai segmen terakhir di bagian URI. Misalnya, Dasar Pemrograman Android Page 79 jiak ID tersebut adalah 9, maka URI menjadi: content://. . . ./9. Untuk mempermudah penambahan id ini dapat digunakan method Uri.withAppendedPath(Uri, pathtambahan). Selain penggunaan id untuk pembatasan query dapat dilakukan dengan menambahkan argumenargumen ke method this.managedQuery (Uri, nama Kolom yang ditampilkan, seleksi,argumen seleksi, sortOrder). d. Broadcast Receiver Merupakan sebuah component yang menerima dan merespon broadcast announcement (siaran pemberitahuan). Banyak broadcast yang berasal dari kode sistem, contohnya, pemberitahuan bahwa zona waktu telah berubah, baterai lemah, baru saja ada pengambilan gambar, atau user baru saja mengganti pengaturan bahasa. Aplikasi juga dapat menginisiasi broadcast-contohnya, untuk memberi tahu aplikasi lain bahwa suatu data telah diunduh ke dalam perangkat dan siap digunakan. Sebuah aplikasi dapat memperoleh beberapa broadcast receiver untuk merespon pemberitahuan yang dianggap penting. Setiap receiver meng-extend class BroadcastReceiver dan dikirim sebagai sebuah objek Intent. Broadcast receiver tidak menampilkan user interface. Namun, akan memulai sebuah activity sebagai respon atas pemberitahuan yang diterima. Atau menggunakan NotificationManager untuk memperingatkan pengguna. Notifikasi akan menarik perhatian user dengan berbagai cara seperti: membuat backlight berkedap kedip, menggetarkan perangkat, memainkan suara notifikasi, dan sebagainya. Menempatkan ikon yang tetap pada status bar yang dapat diakses dan pesannya dapat dibaca langsung oleh user. 3.4.1 Mengaktifkan Komponen Content provider diaktifkan ketika menerima permintaan dari ContentResolver. Tiga component lainnya yaitu activity, service dan broadcast receiver diaktifkan oleh pesan asynchronous yang disebut intent. Intent merupakan object intent yang memegang isi dari pesan. Untuk activity dan service, intent merupakan sebutan aksi yang di-request dengan menentukan URI dari data yang akan ditransmisikan. Contohnya, intent me-request sebuah activity agar menampilkan gambar atau memungkinkan pengguna untuk menyunting sebuah teks. Untuk broadcast receiver, intent merupakan aksi yang diinformasukan. Contohnya, ketika ada announcement bahwa tombol kamera telah ditekan. Dasar Pemrograman Android Page 80 Ada beberapa method untuk mengaktifkan setiap tipe component, yaitu: a. Sebuah activity dijalankan dengan cara melewatkan sebuah object intent ke dalam startActivity() atau startActivityForResult() (jika activity tersebut ingin mengembalikan hasil). Contohnya, jika sebuah activity untuk mengambil foto dijalankan, maka kemungkinan user ingin agar foto yang baru saja diambil bisa ditampilkan. b. Sebuah service dijalankan (atau diinstruksikan pada service yang sedang berjalan) dengan cara melewatkan sebuah object intent ke dalam method startService(). Android akan memanggil service onStart() dan melewatkan object intent. Sebuah intent juga dapat dilewatkan ke dalam method bindService() untuk menjalin koneksi yang sedang berlangsng di antara component yang dipanggil dan service yang dituju. c. Aplikasi dapat mengirimkan broadcast dengan cara melewatkan sebuah obyek intent ke dalam method sendBroadcast(), sendOrdered-Broadcast(), dan sendStickyBroadcast() dalam berbagai variasi. Android akan mengantarkan intent kepada semua broadcast receiver dengan cara memanggil method onReceive().\ d. Untuk menampilkan content provider dengan cara memanggil query() pada ContentResolver. 3.4.2 Menonaktifkan Komponen Content provider hanya akan aktif pada saat merespon request dari ContentResolver, dan broadcast receiver hanya akan aktif pada saat merespon pesan yang disebarkan (broadcast message). Jadi, kedua komponen ini tidak perlu dinonaktifkan. Di sisi lain, activity menyajikan user interface. Activity berinteraksi dengan pengguna dalam jangka waktu yang lama, dan tetap aktif, bahkan pada saat idle. Demikian pula dengan service. Untuk itu, android mempunyai method untuk menonaktifkan activity dan service dengan cara tertentu. a. Activity dapat dinonaktifkan dengan cara memanggil method finish(). Satu activity dapat menonaktifkan activity lainnya (apabila dijalankan dengan with startActivityForResult() dengan cara memanggil finishActivity(). b. Service dapat dinonaktifkan dengan cara memanggil method stopSelf() atau Context.stopService(). Dasar Pemrograman Android Page 81 3.4.3 File Manifest Sebelum Android menjalankan komponen aplikasi, maka system harus mengetahui komponen yang ada dengan cara membaca file AndroidManifest.xml. Untuk itu, semua aplikasi yang akan dijalankan harus dideklarasikan pada file manifest ini. File manifest merupakan root dari direktori project. Selain untuk mendeklarasikan komponen aplikasi, file ini juga berfungsi untuk, diantaranya: a. Mengidentifikasi izin akses aplikasi. b. Mendeklarasi minimum API level yang dibutuhkan aplikasi. c. Mendeklarasikan hardware dan software yang dibutuhkan aplikasi, misalnya: camera, bluetooth services, atau multitouch screen. d. API library yang dibutuhkan system, misalnya untuk Google maps, dan lain-lain. e. Mendeklarasikan persyaratan aplikasi, dan masih banyak yang lainnya. Deklarasi Komponen Aplikasi Contohnya, sebuah activity dideklarasikan sebagai berikut. <?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application> </manifest> Nama atribut elemen <activity> menyebutkan turunan dari Activity yang mengimplementasikan activity. Icon dan label menunjuk pada source file yang berisi ikon dan label yang dapat ditampilkan untuk mewakili activity. Komponen yang lain dideklarasikan dengan cara yang sama, contohnya elemen <service> untuk service, elemen <receiver> untuk broadcast receiver, dan elemen <provider> untuk content provider. Activity, service dan content provider yang dideklarasikan di dalam manifest tidak dapat dilihat oleh sistem, sehingga tidak dijalankan. Namun, broadcast receiver dapat dideklarasikan baik dalam manifest maupun dibuat secara dinamis dengan menggunakan kode (sebagai obyek BroadcastReceiver) dan akan diregistrasikan di dalam sistem dengan memanggil Context.registerReceiver(). Dasar Pemrograman Android Page 82 3.4.4 Sumber Aplikasi Sebuah aplikasi Android tidak hanya terdiri dari sekedar kode, untuk itu membutuhkan sumber daya yang terpisah dari kode sumber, seperti gambar, file audio, dan apapun yang berkaitan dengan presentasi visual dari aplikasi. Misalnya, harus mendefinisikan animasi, menu, style, warna, dan tata letak antarmuka pengguna aktivitas dengan file XML. Dengan menggunakan sumber daya aplikasi memudahkan untuk memperbarui berbagai karakteristik aplikasi tanpa memodifikasi kode dengan ini bisa mengoptimalkan aplikasi untuk berbagai konfigurasi perangkat (seperti bahasa yang berbeda dan ukuran layar). Untuk setiap sumber daya yang dimasukkan dalam proyek Android, SDK membangun alat mendefinisikan ID integer unik, yang dapat digunakan untuk referensi sumber daya dari kode aplikasi atau dari sumber lain yang akan didefinisikan dalam XML. Sebagai contoh, jika aplikasi berisi file gambar bernama logo.png (disimpan dalam direktori res/drawable/), SDK menghasilkan sumber daya ID bernama R.drawable.logo, yang dapat digunakan untuk referensi gambar dan dimasukkan kedalam tampilan Layout aplikasi yang dibuat. 3.4.5 Intent Filter Object intent dapat menampilkan nama target komponen secara eksplisit. Jika hal ini dilakukan, Android akan menemukan komponen (berdasarkan pada deklarasi di dalam file manifest) dan mengaktifkannya. Namun jika target tidak disebutkan secara eksplisit, maka Android harus dapat menentukan komponen yang cocok untuk merespon intent tersebut. Berikut ini adalah contoh tambahan dari contoh sebelumnya yang akan menambahkan dua intentfilterke dalam activity. <?xml version="1.0" encoding="utf-8"?> <manifest . . . > <application . . . > <activity android:name="com.example.project.FreneticActivity" android:icon="@drawable/small_pic.png" android:label="@string/freneticLabel" . . . > <intent-filter . . . > <action android:name="android.intent.action.MAIN" /> Dasar Pemrograman Android Page 83 <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter . . . > <action android:name="com.example.project.BOUNCE" /> <data android:mimeType="image/jpeg" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> . . . </application> </manifest> Contoh pada filter pertama, kombinasi dari aksi android.intent.action.MAIN dan kategori android.intent.category.LAUNCHER adalah hal yang paling umum. Kedua aksi ini menunjukkan bahwa activity akan dijalankan sebagai application launcher, yang dapat dijalankan oleh pengguna di dalam daftar aplikasi yang muncul di layar. Dengan kata lain, activity merupakan entry point dari aplikasi, yang akan muncul ketika pengguna memilih aplikasi tersebut.Filter yang kedua mendeklarasikan sebuah aksi yang dapat menampilkan tipe data khusus. Sebuah component dapat memiliki beberapa intent filter, yang setiapnya mendeklarasikan kemampuan yang berbeda-beda. Jika sebuah component tidak mempunyai filter apapun, maka component dapat diaktifkan oleh intent yang langsung menunjuk component tersebut sebagai tujuannya. Intent filter dapat diinstansi secara langsung sebagai IntentFilter obyek untukbroadcast receiver yang dibuat dan dinyatakan dalam kode. Semua filter yang lain diatur di dalam manifest. Tiga komponen penting dari aplikasi Android adalah activities, services, dan broadcast receivers. Intent diaktifkan dengan dipanggil melalui pesan. Pesan Intent adalah fasilitas untuk akhir run-time yang mengikat antara komponen dalam aplikasi yang sama atau berbeda. Intent sendiri adalah struktur data pasif memegang deskripsi abstrak dari operasi yang akan dilakukan, atau sering disebut dengan kasus broadcast. Deskripsi dari sesuatu yang telah terjadi dan sedang diumumkan. Ada mekanisme terpisah untuk menyampaikan intent untuk setiap jenis komponen: Dasar Pemrograman Android Page 84 a. Sebuah objek Intent dilewatkan Activity.startActivityForResult() Context.startActivity() ke atau untuk memulai activity atau mendapatkan aktivitas yang ada untuk melakukan sesuatu yang baru. (Ini juga dapat dikirimkan ke Activity.setResult() untuk mengembalikan informasi untuk kegiatan yang disebut startActivityForResult()). b. Sebuah objek Intent dilewatkan ke Context.startService() untuk memulai services atau memberikan instruksi baru pada services yang sedang berlangsung. Demikian pula, sebuah Intent dapat dikirimkan ke Context.bindService() untuk membuat sambungan antara komponen panggilan dan target services. Secara opsional dapat memulai services jika tidak sudah berjalan. c. Objek Intent diteruskan Context.sendBroadcast(), ke salah satu metode broadcast Context.sendOrderedBroadcast(), Context.sendStickyBroadcast()) dikirim (seperti atau ke semua penerima siaran tertarik. Banyak jenis broadcast berasal dari kode sistem. Dalam setiap kasus, sistem Android menemukan activity yang sesuai, services, atau broadcast receivers untuk menanggapi Intent, menginisiasi jika diperlukan. Tidak ada tumpang tindih dalam sistem ini: maksud Broadcast dikirim hanya untuk menyiarkan pada penerima, tidak pernah dengan activity atau services. Intent dilewatkan ke startActivity() yang disampaikan hanya untuk suatu activity, tidak pernah ke penerima services atau broadcast, dan sebagainya. Dokumen ini dimulai dengan deskripsi objek Intent. Kemudian menggambarkan aturan Android yang digunakan untuk memetakan komponen intent - bagaimana menyelesaikan komponen yang harus menerima pesan. Untuk Intent yang tidak secara eksplisit nama komponen sasaran, proses ini melibatkan pengujian terhadap objek Intent filter terkait dengan target potensial. Intents object Sebuah objek Intent adalah bundle of information. Berisi informasi yang menarik bagi komponen yang menerima intent (seperti tindakan yang akan diambil dan data untuk bertindak atas) ditambah informasi yang menarik bagi sistem Android (seperti kategori komponen yang Dasar Pemrograman Android Page 85 harus menangani maksud dan instruksi bagaimana untuk memulai aktivitas target). Pada prinsipnya, dapat memuat: Component Name Nama dari komponen yang harus menangani tujuannya. Bidang ini adalah objek ComponentName - kombinasi dari nama kelas yang memenuhi syarat dari komponen sasaran (misalnya "com.example.project.app.FreneticActivity") dan nama paket atur di file manifest dari aplikasi dimana komponen tersebut berada (misalnya, "com.example.project"). Bagian paket nama komponen dan nama paket yang ditetapkan dalam manifest tidak harus sama. Nama komponen opsional. Jika sudah diatur, objek Intent dikirimkan ke sebuah instance dari kelas yang ditunjuk. Jika tidak diatur, Android menggunakan informasi lainnya di objek Intent untuk menemukan target yang cocok - lihat Resolusi Intent, nanti dalam dokumen ini. Nama komponen ditentukan oleh setComponent(), setClass(), atau setClassName() dan dibaca oleh getComponent(). Action Sebuah string penamaan action yang akan dilakukan - atau, dalam kasus broadcast intents, action yang terjadi dan sedang dilaporkan. Kelas Intent mendefinisikan beberapa konstanta tindakan, termasuk ini: Constant Table 3.1 Action Target Component Action ACTION_CALL ACTION_EDIT Activity activity ACTION_MAIN activity ACTION_SYNC activity ACTION_BATTERY_LOW ACTION_HEADSET_PLUG broadcast receiver broadcast receiver ACTION_SCREEN_ON ACTION_TIMEZONE_CHANGED broadcast receiver broadcast receiver Dasar Pemrograman Android Melakukan Panggilan Telepon Menampilkan data bagi pengguna untuk mengedit. Start up sebagai kegiatan awal tugas, tanpa data input dan ada output dikembalikan. Menyinkronkan data pada server dengan data pada perangkat mobile. Sebuah peringatan bahwa baterai rendah. Headset telah terpasang ke dalam perangkat, atau dicabut dari itu. Layar telah diaktifkan. Pengaturan untuk zona waktu telah berubah. Page 86 Lihat deskripsi Intent kelas untuk daftar lengkap kategori method addCategory() untuk menempatkan kategori dalam suatu objek Intent, removeCategory() untuk menghapus sebuah kategori sebelumnya ditambahkan, dan getCategories() untuk mendapat himpunan semua kategori sedang dalam objek. Data URL dari data yang akan bertindak dan jenis MIME dari data tersebut. Tindakan yang berbeda dipasangkan dengan berbagai jenis spesifikasi data. Sebagai contoh, jika field tindakan adalah ACTION_EDIT, field data akan berisi URL dari dokumen yang akan ditampilkan untuk mengedit. Jika ACTION_CALL, bidang data akan mengirim URL dengan nomor yang akan dipanggil. Demikian pula, jika tindakan itu ACTION_VIEW dan field data merupakan http:URL, aktivitas penerima akan diminta untuk men-download dan menampilkan data apa pun mengacu pada URL. Ketika melakukan pencocokan Intent untuk komponen yang mampu menangani data, sering kali penting untuk mengetahui jenis data (tipe MIME-nya) selain URL-nya. Misalnya, komponen dapat menampilkan data gambar tidak boleh diminta untuk memutar file audio. Dalam banyak kasus, jenis data dapat disimpulkan dari URL - khususnya konten: URL, yang mengindikasikan bahwa data terletak pada perangkat dan dikontrol oleh content provider (lihat diskusi terpisah pada content provider). Tapi jenis ini juga dapat secara eksplisit diatur dalam objek Intent. Method setData() menentukan data hanya sebagai sebuah URL, setType() menetapkan hanya sebagai tipe MIME, dan setDataAndType() menetapkan itu baik sebagai sebuah URL dan jenis MIME. URL dibaca oleh getData() dan jenis oleh getType(). Category Sebuah string yang berisi informasi tambahan tentang jenis komponen yang harus menangani tujuannya. Setiap jumlah deskripsi kategori dapat ditempatkan dalam suatu objek Intent. Seperti halnya untuk tindakan, kelas Intent mendefinisikan konstanta kategori, termasuk ini: Constant Dasar Pemrograman Android Meaning Page 87 CATEGORY_BROWSABLE Target Activity dapat dengan aman dipanggil oleh browser untuk menampilkan data direferensikan oleh link - misalnya, gambar atau pesan e-mail. CATEGORY_GADGET Activity tersebut dapat ditempelkan dalam Activity lain yang menjadi host gadget. CATEGORY_HOME Activity ini menampilkan layar awal, layar pertama pengguna melihat bila perangkat diaktifkan atau ketika tombol HOME ditekan. CATEGORY_LAUNCHER Activity ini dapat menjadi activity awal sebuah tugas dan terdaftar dalam peluncur aplikasi top level. CATEGORY_PREFERENCE Target Activity ini adalah sebuah panel preferensi. Extras Pasangan key-value untuk informasi tambahan yang harus dikirim ke komponen penanganan Intent. Sama seperti beberapa tindakan dipasangkan dengan jenis tertentu dari data URL, beberapa dipasangkan ACTION_TIMEZONE_CHANGED dengan tambahan tertentu. Misalnya, Intent memiliki "zona waktu" ekstra yang mengidentifikasi zona waktu baru, dan ACTION_HEADSET_PLUG memiliki "kondisi" ekstra menunjukkan apakah headset sekarang ditancapkan atau dicabut, serta "nama" tambahan untuk jenis headset. Untuk menciptakan tindakan SHOW_COLOR, nilai warna akan ditetapkan dalam sebuah pasangan keyvalue ekstra. Obyek Intent memiliki serangkaian method put…() untuk memasukkan berbagai jenis data tambahan dan satu set of get…() untuk membaca data. Metode-metode paralel yang untuk objek Bundle. Bahkan, tambahan dapat diinstal dan dibaca sebagai Bundle menggunakan method putExtras() dan getExtras(). Flags Flags berbagai jenis. Banyak menginstruksikan sistem Android bagaimana untuk memulai suatu kegiatan (misalnya, yang tugas activity ini harus dimiliki) dan cara memanfaatkannya setelah itu diluncurkan (misalnya, apakah itu termasuk dalam daftar kegiatan baru). Flags didefinisikan dalam kelas Intent. Dasar Pemrograman Android Page 88 Intents resolution Intent dapat dibagi menjadi dua kelompok: a. Intent eksplisit menunjuk komponen target dengan nama (kolom nama komponen, sebutkan sebelumnya, memiliki seperangkat nilai). Karena nama komponen umumnya akan tidak diketahui pengembang aplikasi lain, intent eksplisit biasanya digunakan untuk aplikasi internal pesan - seperti suatu activity memulai services bawahan atau meluncurkan sister activity. b. Intent implisit tidak menyebutkan target (field untuk nama komponen adalah kosong). Intent implisit yang sering digunakan untuk mengaktifkan komponen dalam aplikasi lain. Android memberikan sebuah intent eksplisit untuk sebuah instance dari kelas target yang ditunjuk. Tidak ada dalam objek Intent selain hal-hal komponen nama untuk menentukan komponen harus mendapatkan Intent. Sebuah strategi yang berbeda diperlukan untuk intent implisit. Dengan tidak adanya target yang ditunjuk, sistem Android harus menemukan komponen terbaik (atau komponen) untuk menangani intent - activity atau services untuk melakukan activity yang diminta atau seperangkat broadcast receivers untuk menanggapi pengumuman broadcast. Ia melakukannya dengan membandingkan isi dari objek Intent untuk Intent filter, struktur yang terkait dengan komponen yang berpotensi dapat menerima Intents. Filter menyampaikan kemampuan komponen dan membatasi penanganan Intents. Membuka komponen untuk kemungkinan menerima Intents implisit dari jenis yang disampaikan. Jika komponen tidak memiliki filter intent, maka hanya dapat menerima Intents eksplisit. Sebuah komponen dengan filter dapat menerima baik Intents eksplisit dan implisit. Hanya tiga aspek dari suatu obyek Intent dikonsultasikan ketika objek diuji terhadap Intent Filter: a. Action b. Data (kedua jenis URL dan tipe data) c. Category Dasar Pemrograman Android Page 89 Ekstra dan Flags tidak berperan dalam mengatasi komponen yang menerima sebuah intent. Intent Filters Untuk menginformasikan sistem yang Intent Implisiat yang dapat menangani, activity, services, dan broadcast dapat memiliki satu atau lebih Intent Filter. Setiap filter menggambarkan kemampuan komponen, bahwa satu set Intent komponen bersedia menerima. Ini untuk Intents Filter dari tipe yang diinginkan, sementara untuk menyaring Intent yang tidak diinginkan - Intent implisit yang tidak diinginkan (yang tidak memberi nama kelas target). Intent eksplisit selalu dikirim ke target, tidak peduli apa yang dikandungnya, filter tidak dikonsultasikan. Tapi intent implisit disampaikan ke komponen hanya jika dapat melewati salah satu filter komponen itu. Sebuah komponen memiliki filter yang terpisah untuk setiap pekerjaan yang dapat dilakukan, setiap tampilan bisa menyajikan kepada pengguna. Misalnya, activity NoteEditor, contoh dari aplikasi NotePad memiliki dua filter - satu untuk memulai dengan catatan khusus bahwa pengguna dapat melihat atau mengedit, dan satu lagi untuk mulai dengan catatan kosong dimana user bisa mengisi dan menyimpan. (Semua filter NotePad yang dijelaskan di bagian Contoh NotePad, kemudian) Intent Filter adalah turunan dari kelas IntentFilter. Namun, karena sistem Android harus mengetahui tentang kemampuan dari komponen sebelum dapat memulai komponen tersebut, filter intent umumnya tidak diatur dalam kode Java, tetapi dalam file manifest aplikasi (AndroidManifest.xml) sebagai elemen <intent-filter> . (Satu pengecualian akan menjadi filter untuk broadcast yang Context.registerReceiver(), terdaftar secara dinamis dengan menghubungi mereka langsung dibuat sebagai objek IntentFilter). Filter memiliki kolom yang paralel, data, dan bidang kategori objek Intent. Intent implisit diuji terhadap filter di ketiga wilayah. Untuk disampaikan kepada komponen yang memiliki filter, harus lulus semua tiga tes. Jika gagal bahkan salah satu dari mereka, sistem Android tidak akan mengirimkannya ke komponen - setidaknya tidak berdasarkan filter yang. Namun, karena komponen dapat memiliki filter intent ganda, intent yang tidak lulus melalui satu filter sebuah komponen mungkin membuatnya melalui yang lain. Masing-masing dari tiga tes dijelaskan secara rinci di bawah ini: Dasar Pemrograman Android Page 90 1. Action Test Sebuah elemen <intent-filter> dalam file manifest daftar tindakan sebagai subelements <action>. Sebagai contoh: <intent-filter . . . > <action android:name="com.example.project.SHOW_CURRENT" /> <action android:name="com.example.project.SHOW_RECENT" /> <action android:name="com.example.project.SHOW_PENDING" /> . . . </intent-filter> Sebagai contoh adalah menampilkan, sedangkan obyek Intent menamai hanya satu tindakan, filter dapat berisi lebih dari satu. Daftar ini tidak boleh kosong filter harus mengandung setidaknya satu unsur <action>, atau akan memblokir semua Intent. Untuk lulus tes ini, tindakan yang ditentukan dalam objek Intent harus sesuai dengan salah satu tindakan yang tercantum dalam filter. Jika objek atau filter tidak menentukan tindakan, hasilnya adalah sebagai berikut: Jika filter gagal untuk membuat daftar activity, tidak ada intent untuk untuk menyesuaikan, sehingga semua intent gagal tes. Tidak ada intens yang bisa melewati filter. Di sisi lain, objek Intent yang tidak menentukan suatu activity otomatis lulus uji - selama filter berisi setidaknya satu activity. 2. Category Test Sebuah elemen <intent-filter> juga daftar kategori sebagai subelements. Sebagai contoh: <intent-filter . . . > <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> . . . </intent-filter> Perhatikan bahwa konstanta dijelaskan sebelumnya atas tindakan dan kategori tidak digunakan dalam file manifest. Nilai string penuh digunakan sebagai gantinya. Misalnya, Dasar Pemrograman Android Page 91 "android.intent.category.BROWSABLE" string dalam contoh di atas sesuai dengan konstan CATEGORY_BROWSABLE disebutkan sebelumnya dalam dokumen ini. Demikian pula, string "android.intent.action.EDIT" sesuai dengan konstan ACTION_EDIT. Untuk Intent yang lulus tes kategori, setiap kategori di objek Intent harus sesuai kategori dalam filter. Filter bisa daftar kategori tambahan, tetapi tidak dapat menghilangkan yang Intent. Karena itu, obyek Intent tanpa kategori harus selalu lulus tes ini, terlepas dari apa yang ada di filter. Itu sebagian besar benar. Namun, dengan satu pengecualian, Android memperlakukan semua Intent implisit dilewatkan ke startActivity () seolah-olah mereka mengandung setidaknya satu kategori: "android.intent.category.DEFAULT" (yang CATEGORY_DEFAULT konstan). Oleh karena itu, kegiatan yang bersedia untuk menerima inten implisit harus mencakup "android.intent.category.DEFAULT" di intent filter mereka. (Filter dengan "android.intent.action.MAIN" dan "android.intent.category.LAUNCHER" Pengaturan adalah pengecualian menandai kegiatan yang dimulai dengan tugas baru dan diwakili pada layar peluncur. Mereka dapat termasuk "android.intent category.DEFAULT ". dalam daftar kategori, tetapi tidak perlu) Lihat Menggunakan penyesuaian intent. Data Test Seperti aksi dan kategori, spesifikasi data filter intent yang terkandung dalam sebuah subelement. Dan, seperti dalam kasus-kasus, subelement dapat muncul beberapa kali, atau tidak sama sekali. Sebagai contoh: <intent-filter . . . > <data android:mimeType="video/mpeg" android:scheme="http" . . . /> <data android:mimeType="audio/mpeg" android:scheme="http" . . . /> . . . </intent-filter> Setiap elemen <data> dapat menentukan URL dan jenis data (tipe MIME media). Ada atribut yang terpisah - skema, host, port, dan path - untuk setiap bagian dari URL: scheme://host:port/path Sebagai contoh, di URL berikut: content://com.example.project:200/folder/subfolder/etc Dasar Pemrograman Android Page 92 Skema itu "content", host adalah "com.example.project", port "200", dan pathnya adalah "folder / subfolder / etc". Host dan port bersama-sama merupakan otoritas URL, jika sebuah host yang tidak ditentukan, port diabaikan. Masing-masing atribut adalah opsional, tetapi mereka tidak independen satu sama lain: Untuk otoritas menjadi berarti, skema juga harus ditetapkan. Untuk jalan menjadi berarti, baik skema dan kewenangan harus ditentukan. Ketika URL dalam suatu objek Intent dibandingkan dengan spesifikasi URL di filter, itu dibandingkan hanya pada bagian-bagian dari URL sebenarnya yang disebutkan dalam filter. Misalnya, jika filter hanya menentukan skema, semua URL dengan skema yang cocok dengan filter. Jika filter menentukan skema dan otoritas tetapi tidak ada path, semua URL dengan skema yang sama dan otoritas pertandingan, terlepas dari jalur mereka. Jika filter menentukan skema, otoritas, dan path, hanya URL dengan skema yang sama, otoritas, dan pertandingan path. Namun, spesifikasi path dalam filter dapat berisi wildcard untuk hanya memerlukan pertandingan parsial jalan. Jenis atribut dari elemen <data> menetapkan tipe MIME dari data. Ini lebih sering terjadi pada filter dari URL. Kedua objek Intent dan filter dapat menggunakan wildcard "*" untuk field subtype - misalnya, "text / *" atau "audio / *" - yang menunjukkan setiap pertandingan subtype. Tes data yang membandingkan kedua URL dan tipe data dalam objek Intent untuk jenis URL dan data yang ditetapkan dalam filter. Aturannya adalah sebagai berikut: 1. Sebuah objek Intent yang berisi bukan sebuah URL atau tipe data lulus uji hanya jika filter juga tidak menjelaskan jenis URL atau data. 2. Sebuah objek Intent yang berisi URL tetapi tidak ada tipe data (dan jenis yang tidak dapat disimpulkan dari URL) melewati tes hanya jika URL cocok URL dalam filter dan filter juga tidak menentukan tipe. Ini akan menjadi kasus hanya untuk URL seperti mailto: dan tel: bahwa tidak mengacu pada data aktual. 3. Sebuah objek Intent yang berisi tipe data tetapi tidak URL lulus uji hanya jika filter berisi daftar tipe data yang sama dan juga tidak menentukan URL. 4. Sebuah objek Intent yang berisi URL dan tipe data (atau tipe data dapat disimpulkan dari URL) melewati bagian data jenis tes hanya jika jenisnya cocok dengan jenis yang tercantum dalam saringan. Melewati bagian URL dari tes baik jika URL cocok URL dalam filter atau jika memiliki konten: atau file: URL dan filter tidak menentukan URL. Dengan kata lain, Dasar Pemrograman Android Page 93 komponen dianggap mendukung konten: dan file: data jika daftar penyaring yang hanya tipe data. Jika intent itu dapat melewati filter lebih dari satu activity atau services, pengguna mungkin akan diminta yang komponen untuk mengaktifkan. Exception dimunculkan jika target tidak dapat ditemukan. 3.4.6 Activity dan Task Sebagaimana telah disebutkan sebelumnya, sebuah activity dapat memicu activity yang lain, termasuk yang didefinisikan di dalam aplikasi yang berbeda. Sebagai contoh, jika pengguna menginginkan untuk dapat menampilkan peta jalan dari sebuah lokasi. Telah ada activity yang melakukan hal tersebut, jadi semua activity yang diperlukan ditempatkan sebagai sebuah obyek intent yang dilengkapi dengan semua informasi yang dibutuhkan, dan dilewatkan di dalam startActivity(). Kemudian map viewer akan menampilkan peta yang dibutuhkan. Ketika pengguna menyentuh BACK key, maka activity sebelumnya akan tampil di layar. Pengguna akan berfikir bahwa map viewer tersebut ada di dalam aplikasi yang sama sebagai activity, walaupun pada kenyataannya tidak. Map viewer didefinisikan di dalam aplikasi yang lain yang berjalan di dalam proses aplikasi tersebut. Android menjaga user experience ini dengan cara menjalankan dua activity di dalam task yang sama. Task merupakan sekumpulan activity yang saling terhubung dan diatur dalam sebuah stack. Activity yang ada di posisi paling bawah adalah activity yang memulai task, pada umumnya activity ini yang dipilih pengguna pada application launcher. Sedangkan activity yang terletak paling atas adalah activity yang sedang berjalan atau activity yang berfokus pada aksi dari pengguna. Ketika sebuah activity memicu activity lainnya, maka activity baru akan masuk ke dalam susunan dan menjadi activity yang aktif. Activity sebelumnya akan tetap berada di dalam stack dan ketika pengguna menyentuh tombol BACK, activity tersebut akan dikeluarkan dari dalam stack sehingga activity sebelumnya akan aktif kembali. Susunan tersebut mempunyai object, sehingga apabila sebuah task terdiri dari satu instance dari subclass activity yang sama, contohnya map viewer lebih dari satu- maka susunan tersebut mempunyai entry yang terpisah untuk setiap instance. Activity di dalam susunan tersebut tidak pernah tersusun ulang, hanya keluar dan masuk. Dasar Pemrograman Android Page 94 Task merupakan susunan dari activity-activity, bukan sebuah class atau elemen di dalam file manifest. Sehingga tidak ada cara untuk menentukan nilai dari task yang tidak tergantung pada activity-nya. Nilai dari beberapa task sebagai suatu kesatuan ditentukan di dalam activity yang terletak pada sususan dasar. Contohnya, bagian berikutnya akan berisi tentang “afinitas task”; bahwa nilainya diketahui dari rangkaian persamaan task activity yang terletak pada stack paling dasar. Semua activity di dalam task bergerak bersama sebagai sebuah unit. Task keseluruhan dapat dibawa ke atas permukaan atau dikirim ke layar. Contohnya, task pada saat ini mempunyai empat activity di dalam susunannya, maka terdapat tiga activity yang terletak di bawah activity yang sedang berjalan. Kemudian pengguna menyentuh kunci HOME, maka tampilan akan berpindah ke application launcher, dan memilih sebuah aplikasi. Maka task pada saat itu akan ditempatkan sebagai latar dan activity dasar akan ditampilkan. Dalam waktu singkat, pengguna akan melihat tampilan kembali ke home dan memilih aplikasi yang sebelumnya (task yang sebelumnya). Task itu, dengan keempat activity di dalamnya, dibawa ke permukaan. Ketika pengguna menyentuh back key, tidak akan ditampilkan activity yang baru saja ditinggalkan oleh pengguna (activity dasar pada task sebelumnya), melainkan activity yang ada pada susunan paling atas akan dilepas dan menampilkan activity sebelumnya yang ada di dalam task yang sama. Perilaku di atas adalah perilaku default dari activity dan task. Namun ada beberapa cara untuk memodifikasi semua aspek tersebut. Hubungan antara activity dan task, dan perilaku activity di dalam task, dikendalikan oleh interaksi antara aturan flag yang diatur di dalam intent object, yang memulai activity dan atribut yang terdapat di dalam elemen <activity> di dalam manifest. Sehingga pengirim permintaan dan pemberi respon akan mempunyai informasi yang sama. Dalam hal ini, intent flag yang pokok adalah: a. FLAG_ACTIVITY_NEW_TASK b. FLAG_ACTIVITY_CLEAR_TOP c. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED d. FLAG_ACTIVITY_SINGLE_TOP Atribut pokok <activity> adalah: a. taskAffinity Dasar Pemrograman Android Page 95 b. launchMode c. allowTaskReparenting d. clearTaskOnLaunch e. alwaysRetainTaskState f. finishOnTaskLaunch Bagian berikutnya akan menggambarkan fungsi dari flag dan atribut di atas, bagaimana interaksinya dan atas pertimbangan apakah menggunakan flag tersebut. 3.4.7 Afinitas dan Task Baru Secara default, semua activity di dalam aplikasi mempunyai afinitas (persamaan) satu sama lain, sehingga ada setingan agar semuanya di dalam task yang sama. Sebuah afinitas individual bisa diatur untuk setiap activity menggunakan atribut taskAffinity dari elemen <activity> . Activity yang terdapat di dalam aplikasi yang berbeda dapat menggunakan afinitas yang sama, atau activity yang terdapat di dalam aplikasi yang sama dapat menggunakan afinitas yang berbeda. Afinitas dapat bekerja di dalam dua lingkungan: ketika intent object yang memicu activity mempunyai FLAG_ACTIVITY_NEW_TASK flag allowTaskReparentingactivity , dan ketika atribut tersebut dinyatakan “true”. a. Flag FLAG_ACTIVITY_NEW_TASK Sebagaimana telah disebutkan sebelumnya, secara default, newactivity ketika diluncurkan ke dalam task menggunakan kode startActivity() maka activity tersebut akan dimasukkan ke dalam susunan yang sama dengan activity yang memanggilnya. Tetapi jika intent object startActivity() dilewatkan di dalam taskyang mempunyai flag FLAG_ACTIVITY_NEW_TASK, maka sistem akan mencari task yang berbeda untuk menempatkan activity yang baru tersebut. Ketika flag baru tersebut diimplementasikan, maka dibuatlah sebuah task baru. Namun jika telah ada task yang mempunyai afinitas yang sama dengan activity yang baru, maka activity baru akan diluncurkan di dalam task tersebut. b. Atribut allowTaskReparenting Jika sebuah activity mempunyai atribut allowTaskReparenting yang dinyatakan “true”, maka activity tersebut dapat berpindah dari task-nya dan masuk ke dalam task yang memiliki afinitas ketika task tersebut muncul. Contohnya, ketika ada sebuah activity yang melaporkan Dasar Pemrograman Android Page 96 kondisi cuaca pada kota tertentu dinyatakan sebagai bagian dari sebuah aplikasi pariwisata. Activity tersebut memiliki afinitas yang sama dengan activity lain di dalam aplikasi yang sama (afinitas default) maka pada saat itu diizinkan untuk reparenting. Satu activity memicu laporan cuaca, sehingga activity tersebut memiliki task yang sama. Kemudian aplikasi pariwisata muncul, dan activity laporan cuaca akan ditugaskan kembali dan ditampilkan bersama dengan task tersebut. Jika sebuah file .apk mempunyai lebih dari satu “aplikasi” dari sisi pengguna, lebih baik menugaskan afinitas yang berbeda ke activity yang berbeda yang masing-masing terhubung satu sama lain. 3.4.8 LaunchMode Terdapat empat launch mode berbeda yang bisa ditugaskan pada sebuah elemen <activity> ke dalam atribut launchMode: a. “standard”(mode default) b. “singleTop” c. “singleTask” d. “singleInstance” Mode di atas berbeda dari empat faktor berikut ini: 1. Task apa yang mempunyaiactivity yang akan merespon intent? Bagi mode “standard” dan “singleTop”, task yang berasal dari intent (dan dipanggil startActivity() )- kecuali intent object tersebut mempunyai flag FLAG_ACTIVITY_NEW_TASK. Dalam hal ini, akan dipilih task yang berbeda sebagaimana telah dijelaskan pada bagian sebelumnya. Mode “singleTask” dan “singleInstance” akan menandai activity yang selalu ada di posisi dasar pada task. Mereka memilih sebuah task, dan tidak pernah dimasukkan pada task yang lainnya. 2. Adakah multipleinstance di dalam activity? Bagi mode “standard” dan “singleTop” dapat diinstansikan beberapa kali. Mereka bisa terdapat dalam beberapa task, dan di dalam task tersebut dapat mempunyai multiple instance pada activity yang sama. Pada mode “singleTask” dan “singleInstance”, activity dibatasi Dasar Pemrograman Android Page 97 pada satu instance. Karena activity ini terletak di dasar task, maka batasan ini berarti bahwa tidak ada lebih dari satu instance di dalam task di perangkat tersebut pada saat yang bersamaan. 3. Apakah instance mempunyai activity yang berbeda di dalam task-nya? Activity “singleInstance” berdiri sendiri sebagai satu satunya activity di dalam sebuah task. Jika memicu activity yang lain, maka activity tersebut akan diluncurkan ke dalam task yang lain tanpa memperhatikan mode peluncurannya, sebagaimana jika flag FLAG_ACTIVITY_NEW_TASK ada di dalamintent. Pada beberapa hal, mode “singleInstance” mirip dengan mode “singleTask”. Tiga mode yang lain mengizinkan multiple activity di dalam satu task. Activity “singleTask” akan selalu menjadi activity dasar di dalam task, namun dapat memicu activity lain yang akan ditugaskan dalam task tersebut. Instance dari activity “standard” dan “singleTop” dapat muncul di bagian manapun dalam susunan task. 4. Apakah instance baru dari kelas akan diluncurkan untuk menangangi intent baru? Pada mode “standard” secara default, instance baru akan dibuat untuk merespon setiap intent baru yang muncul. Setiap instance akan menangani satu intent saja. Untuk mode “singleTop”, setiap instance yang ada di dalam kelas akan digunakan kembali untuk menangani intent baru jika activity tersebut ada pada posisi atas di dalam susunan task. Jika tidak terdapat pada posisi atas, maka instance tersebut tidak akan digunakan kembali, dan akan dibuat sebuah intance baru untuk intent baru dan memasukkannya ke dalam susunan. Misalnya, di dalam sebuah susunan task activity terdapat activity dasar A, kemudian activity B, C dan D di atasnya. Maka susunannya akan berpola A-B-C-D. Sebuah intent tiba untuk activity D, jika D mempunyai mode “standard”, maka instance baru akan diluncurkan dan susunannya akan berpola A-B-C-D-D. Namun, jika activity D menggunakan mode “singleTop”, maka instance yang ada diandalkan untuk menangani intent yang baru (karena D ada di posisi paling atas), dan pola susunannya tetap A-B-C-D. Jika intent yang tiba ditujukan untuk activity B, maka instance yang baru untuk B akan tetap diluncurkan, tanpa memperhatikan apakah B menggunakan mode “standard” atau “singleTop” (karena B tidak berada pada posisi atas), maka pola susunannya adalah A-B-C-D- B. Dasar Pemrograman Android Page 98 Sebagaimana disebutkan di atas, tidak akan ada lebih dari satu instance bagi activity mode “singleTask” dan “singleInstance”, maka instance tersebut diharapkan dapat menangani semua intent baru yang muncul. Activity yang menggunakan mode “singleInstance” akan selalu ditempatkan pada posisi atas (karena satu satunya activity di dalam task) maka akan selalu menempati posisi untuk menangani intent. Namun activity “singleTask” dapat mempunyai atau tidak mempunyai activity lain di atasnya. Jika ada activity lain, maka activity ini tidak pada posisi untuk menangani intent. Dan intent akan dihapus. (Walaupun intent ini dibuang, kedatangannya tetap akan menyebabkan task dimunculkan dan tetap ada di permukaan). Ketika activity yang ada diminta untuk menangani intent baru, intent object akan dilewatkan ke activity dengan memanggil onNewIntent(). (intent object yang diawali oleh activity akan diambil dengan memanggil getIntent()). Ingatlah bahwa ketika sebuah instanceactivity dibuat untuk menangani sebuah intent, pengguna dapat menyentuh tombol back untuk kembali ke keadaan layar sebelumnya (activity sebelumnya). Namun jika instance yang sudah ada menangani intent baru, maka pengguna tidak dapat menyentuh tombol back untuk kembali ke keadaan sebelum intent datang. 3.4.9 Membersihkan Stack Jika pengguna meninggalkan task untuk waktu yang lama, sistem akanmembersihkan task semua activity kecuali activitydasar. Ketika pengguna kembali ke task lagi, maka pengguna akan melihat tampilan sebagaimana ketika pengguna meninggalkannya, kecuali bila activity awal dijalankan.Setelah beberapa saat, pengguna akan meninggalkan apa yang sedang dilakukan sebelumnya dan kembali ke task untuk memulai activity yang lain. Secara umum,ada beberapa atribut activity yang dapat digunakan untuk mengendalikan perilaku ini dan memodifikasinya: a. Atribut alwaysRetainTaskState - Jika atribut ini dinyatakan “true” pada activity dasar di sebuah task, maka perilaku default yang baru saja dijabarkan tidak akan terjadi. Karena task akan menahan semua activity untuk tetap berada di dalam susunan meskipun dalam jangka waktu yang lama b. Atribut clearTaskOnLaunch - Jika atribut ini dinyatakan “true” pada activity dasar di sebuah task, maka susunan akan dibersihkan hingga ke dasar, kapanpun pengguna Dasar Pemrograman Android Page 99 meninggalkan task hingga kembali. Dengan kata lain, berlawanan dengan alwaysRetainTaskState, dimana pengguna akan selalu kembali kepada kondisi ketika task ditinggalkan. c. Atribut finishOnTaskLaunch- Atribut ini mirip dengan clearTaskOnLaunch, namun beroperasi hanya pada activity tunggal, tidak pada keseluruhan task. Atribut ini juga dapat menyebabkan activity lain keluar dari susunan, termasuk activity dasar. Ketika nilainya dinyatakan “true”, maka activity yang tersisa adalah sebagian activity yang tersisa di dalam task pada saat itu. Apabila pengguna meninggalkannya dan kembali kepada task tersebut, maka task itu telah hilang. Ada cara lain untuk membuat activity dibersihkan dari susunan. Jika intent object termasuk ke dalam flag FLAG_ACTIVITY_CLEAR_TOP , dan tujuan task mempunyai instance dari jenisactivity yang harus menangani intent di dalam susunan, maka semua activity di atas semua instance akan dibersihkan sehingga instance akan tetap ada di atas susunan dan merespon intent. Jika mode peluncuran activity tersebut adalah “standard”, maka activity itu tetap dibersihkan dari susunan, dan instance baru akan diluncurkan untuk menangani instance yang datang. Hal ini dikarenakan instance yang baru selalu dibuat untuk intent baru ketika mode peluncuran activity adalah “standard”. Flag yang paling banyak digunakan adalah FLAG_ACTIVITY_CLEAR_TOP yang akan terhubung dengan FLAG_ACTIVITY_NEW_TASK. Ketika digunakan bersama, kedua flag ini akan menempatkan activity yang ada di task yang lain dan menempatkannya pada posisi agar dapat merespon intent. 3.4.10 Memulai Task Sebuah activity dapat diatur menjadi entry point untuk sebuah task dengan memberikan intent filter “android.intent.action.MAIN” “android.intent.category.LAUNCHER” yang ditentukan sebagai aksi dan sebagai kategori. Filter ini akan menampilkan ikon dan label acvitivity di application launcher, memberikan akses kepada pengguna untuk meluncurkan task dan kembali ke applicaion launcher kapan saja pengguna menginginkannya. Kemampuan yang kedua ini sangatlah penting: pengguna harus dapat meninggalkan task dan dapat kembali lagi nantinya. Dalam hal ini, dua mode peluncuran yang menandai activity Dasar Pemrograman Android Page 100 untuk memulai task; “singleTask” dan “singleInstance” harus digunakan hanya ketika activity mempunyai filter “MAIN” dan “LAUNCHER”. Coba bayangkan, apa yang akan terjadi apabila filter tersebut hilang?. Sebuah intent akan meluncurkan activity mode “singleTask”, memulai sebuah task baru, dan pengguna akan membutuhkan waktu lebih lama untuk bekerja pada task tersebut. Kemudian, pengguna akan menyentuh tombol home. Berikutnya task akan diperintahkan untuk bekerja di latar dan hilang dari layar home. Dan karena tidak direpresentasikan di dalam application launcher, pengguna tidak dapat kembali ke task tersebut. Flag FLAG_ACTIVITY_NEW_TASK juga mengalami masalah yang sama. Jika flag ini menyebabkan activity untuk memulai task baru dan pengguna menekan tombol home untuk meninggalkannya, maka harus ada navigasi lain untuk memberikan akses kembali. Sejumlah entitas (seperti notification manager) selalu memulai activity pada task eksternal, bukan di dalam bagiannya, maka entitas tersebut selalu meletakkan flag FLAG_ACTIVITY_NEW_TASK di dalam intent yang dilewatkan ke startActivity(). Jika terdapat activity yang dapat diminta oleh entitas eksternal yang mungkin menggunakan flag ini, maka berhati hatilah dengan memberikan cara pada pengguna untuk kembali ke task yang dimulai sebelumnya. Pada kasus jika tidak ingin pengguna dapat kembali ke activity sebelumnya, tentukan nilai pada finishOnTaskLaunchdi elemen <activity> menjadi “true”. 3.5 Proses dan Thread 3.5.1 Proses Proses adalah sesuatu dimana sebuah komponenberjalan dikendalikan oleh file manifest. Elemenkomponen <activity>, <service>, <receiver>, dan <provider> mempunyai atribut process yang akan menentukan sebuah proses dimana komponen akan berjalan. Atribut ini dapat diatur sehingga setiap komponen akan berjalan pada prosesnya masing-masing, atau beberapa komponen akan berbagi sebuah proses sementara dan yang lainnya tidak. Komponen tersebut juga dapat diatur sehingga aplikasi yang berbeda dapat berjalan pada proses yang sama, sebagaimana dilakukan pada Linux, yaitu aplikasi dapat digunakan oleh ID pengguna dan izin akses yang sama. Elemen <application> juga mempunyai atribut process untuk mengatur nilai default yang akan diaplikasikan pada semua komponen. Dasar Pemrograman Android Page 101 Semua komponen akan diinstansi pada thread utama pada proses yang telah ditentukan, dan sistem memanggil komponen yang dikirim dari thread tersebut. Setiap instance tidak akan dibuatkan thread yang terpisah. Sehingga method yang merespon pemanggilan tersebut seperti View.onKeyDown() yang akan melaporkan aksi pengguna dan notifikasi siklus hidup yang akan dibahas nanti pada bagian Siklus Hidup Komponen akan selalu berjalan pada thread utama di dalam proses. Artinya tidak ada komponen yang akan berjalan pada waktu lama atau memblokir operasi (seperti operasi jaringan atau komputasi loop) ketika dipanggil oleh sistem, karena hal ini akan memblokir komponen lain yang ada di dalam proses. Untuk menanganinya, buatlah thread untuk operasi yang membutuhkan waktu lama. Android dapat mematikan sebuah proses pada saat tertentu, ketika kondisi memori rendah dan ada proses lain harus melayani pengguna dengan segera. Komponen aplikasi yang berjalan di proses akan dimatikan pada saat itu. Sebuah proses akan dijalankan kembali proses tersebut dibutuhkan oleh aplikasi. Ketika sebuah proses dimatikan, Android akan mempertimbangkan kepentingannya terhadap pengguna. Contohnya, jika ada dua proses activity,yang tampil dan tidak tampil di layar, maka android akan mematikan proses yang tidak sedang tampil di layar. Keputusan untuk mematikan proses itu sendiri tergantung pada komponen yang berjalan pada proses tersebut. 3.5.2 Thread Jika ingin membatasi aplikasi menjadi proses tunggal, maka akan ada saat dimana harus membuat sebuah thread untuk melakukan pekerjaan pada layar. Karena interface harus dapat memberikan respon cepat kepada pengguna, maka thread yang bertanggung jawab terhadap sebuah activity tidak boleh memakan waktu lama seperti mengunduh file dari jaringan. Proses yang membutuhkan waktu lama harus dibuatkan sebuah thread baru. Thread dibuat dengan menggunakan bahasa standar Java menjadi object Thread. Android menyediakan beberapa class yang dapat digunakan untuk mengatur thread, yaitu Looper untuk menjalankan pesan yang berkesinambungan (looping message), Handler untuk memproses pesan, dan HandlerThread untuk mengatur thread dengan pesan berkesinambungan. Dasar Pemrograman Android Page 102 3.5.3 Remote Procedure Call (RPC) Android mempunyai mekanisme yang ringan untuk RPC, yaitu ketika memanggil method lokal dan mengeksekusinya secara remote (di dalam proses yang lain), dengan hasil yang bisa didapatkan oleh pemanggil. Hal ini membutuhkan proses pengendapan pemanggilan method dan semua data yang ada di dalamnya pada tingkat dimana sistem operasi dapat mengerti, mentransmisikannya dari proses lokal dan memberikan ruangan pada proses remote dan memberikan alamat, mengumpulkannya dan menetapkan panggilan pada lokasi tersebut. Pengembalian nilai harus dapat ditransmisikan ke arah sebaliknya. Android menyediakan semua kode untuk pekerjaan tersebut, sehingga programmer dapat berkonsentrasi kepada penetapan dan implementasi dari antar muka RPC itu sendiri. Antar muka RPC hanya dapat berisi method. Secara default, semua method dieksekusi secara sinkron (method lokal akan memblokir hingga method remote selesai dilakukan), bahkan jika tidak ada pengembalian nilai. Secara singkat, mekanisme kerjanya adalah sebagai berikut: Pertama-tama mulai dengan mendeklarasikan antar muka RPC yang akan diimplementasikan dengan menggunakan IDL (Interface Definition Language). Berdasarkan deklarasi tersebut, tool AIDL (Android Interface Definition Language) akan menghasilkan (generate) definisi interface yang harus tersedia untk digunakan oleh method lokal dan remote. Inner class mempunyai semua kode yang dibutuhkan untuk mengatur RPC atas interface yang dideklarasikan menggunakan IDL. Kedua inner class tersebut mengimplementasikan antar muka IBinder . Satu inner class digunakan secara lokal dan intern oleh sistem. Inner class yang lainnya, yang disebut Stub, akan meng-extend kelas Binder. Class ini berisi deklarasi method dalam antar muka RPC yang telah dideklarasikan sebelumnya yang akan digunakan untuk melaksanakan pemanggilan IPC. Lalu membuat turunan (subclass) Stub untuk mengimplementasikan semua method. Secara khusus, proses remote akan diatur oleh sebuah service (karena service dapat memberitahukan kepada sistem tentang proses dan hubungannya dengan prosesyang lain). Service ini akan mempunyai file interface yang dihasilkan oleh toolAIDL dan turunan Stub yang akan diimplementasikan oleh method RPC. Penerima service (client) hanya akan mempunyai Dasar Pemrograman Android Page 103 interface yang dihasilkan oleh tool tersebut. Berikut ini adalah cara kerja koneksi service dan client: a. Client lokal akan mengimplementasikan onServiceDisconnected() method onServiceConnected() dan sehingga dapat dinotifikasi ketika berhasil terhubung dengan service remote. Dan ketika koneksi tersebut selesai, dapat memanggil method bindService() untuk mengatur ulang koneksi berikutnya. b. Method onBind() dari service dapat diimplementasikan, baik untuk menerima atau menolak koneksi, tergantung dari intent yang diterima (intent akan dilewatkan ke bindService()). Jika koneksi diterima, maka akan mengembalikan instance dari turunan Stub. c. Jika service menerima onServiceConnected() koneksi, maka Android akan memanggil method client dan melewatkannya ke obyek IBinder, sebuah proxy untuk turunan Stub akan diatur oleh service. Melalui proxy, client akan melakukan panggilan ke service remote. 3.5.4 Method Thread-Safe Pada beberapa konteks, method akan diimplementasikan dan dapat dipanggil dari satu thread atau lebih, oleh karena itu method tersebut harus ditulis secara thread-safe. Setiap method dapat dipanggil secara remote, seperti mekanisme RPC yang dibahas pada bagian sebelumnya. Ketika pemanggilan method diimplementasikan pada objectIBinder yang berasal dari dalam proses yang sama di IBinder, method akan dieksekusi didalam thread yang memanggilnya. Namun, ketika panggilan berasal dari proses yang lain, maka method akan dieksekusi di thread dari kumpulan thread yang dijalankan oleh Android pada proses yang sama dengan IBinder, method tersebut tidak akan dieksekusi di dalam thread utama di dalam proses. Contohnya, ketika service dijalankan, method onBind() akan dipanggil dari thread utama yang ada di dalam proses, method yang diimplementasikan di dalam object yang dikembalikan onBind() akan dipanggil dari thread yang ada pada kumpulan thread. Mengingat thread dapatmempunyai lebih dari satu client, maka ada lebih dari satu kumpulan thread yang dapat menggunakan method IBinder yang sama pada saat yang sama. Method IBinder harus diimplementasikan ke dalam thread-safe. Dasar Pemrograman Android Page 104 Content provider dapat menerima permintaan data dari proses yang lain. Walaupun kelas ContentResolver dan ContentProvider menyembunyikan detil komunikasi interproses. Method ContentProvider yang merespon query(), insert(), delete(), update(), permintaan tersebut adalah method dan getType() yang dipanggil dari kumpulan thread dari proses ContentProvider, bukan dari thread utama di dalam proses. Karena methodmethod ini dapat dipanggil dari sejumlah thread manapun pada saat yang sama, maka harus diimplementasikan secara thread-safe. 3.6 Siklus Hidup Komponen 3.6.1 Siklus Hidup Activity Sebuah activity mempunyai tiga keadaan: a. Active, ketika ada di permukaan layar (di atas tumpukan activity pada task yang saat itu sedang berjalan). Activity inilah yang berkonsentrasi pada aksi dari pengguna. b. Pause, ketika tidak lagi berkonsentrasi pada pengguna namun tetap tampil di layar. Adanya activity lain yang tampil di atasnya, activity tersebut bisa tampil secara transparan atau tidak memenuhi tampil full screen, sehingga beberapa activity yang berstatus pause tetap dapat terlihat. Activity berstatus pause tetap berjalan (menjaga semua kondisi, informasi, dan tetap terkait pada window manager), namun dapat dinonaktifkan oleh sistem kapan saja pada saat memori lemah. c. Stop, ketika terhalangi sepenuhnya oleh activity lain. Pada status ini, kondisi dan semua informasi tetap berjalan. Namun, activity tidak terlihat oleh pengguna dan akan dinonaktifkan oleh sistem ketika memori dibutuhkan di lokasi yang lain. Jika sebuah activity berstatus pause atau stop, maka sistem dapat menyingkirkannya dari memori dengan cara memanggil method finish() atau menonaktifkannya begitu saja. Ketika activity tersebut dipanggil lagi oleh pengguna, maka activity akan di-restart dan dikembalikan (restore) pada kondisi sebelumnya. Setiap perubahan status activity akan mengeluarkan notifikasi yang dapat dilakukan dengan cara memanggil protected method berikut ini: a. void onCreate(Bundle savedInstanceState) b. void onStart() Dasar Pemrograman Android Page 105 c. void onRestart() d. void onResume() e. void onPause() f. void onStop() g. void onDestroy() Semua method di atas saling terkait dan dapat di-override untuk melakukan pekerjaan yang sesuai ketika terjadi perubahan status. Semua activity harus mengimplementasi onCreate() untuk melakukan pengaturan awal ketika object pertama kali diinstansi. Ada beberapa method yang akan mengimplementasi onPause() untuk menjalankan perubahan data menghentikan interaksi dengan pengguna. Implementasi dari method siklus hidup activity harus selalu memanggil versi superclass. Contoh kode yang digunakan seperti berikut ini. protectedvoid onPause(){ super.onPause(); ... } Secara keseluruhan, tujuh method di atas mendefinisikan keseluruhan siklus hidup sebuah activity. Ada beberapa nested loop yang dapat dipantau dengan mengimplementasikan method tersebut: a. Entire Lifetime, masa hidup activity dimulai pada saat method onCreate() dipanggil hingga method onDestroy() dipanggil. Activity akan memulai aturan pertama pada kondisi “global” pada onCreate() dan melepaskan semua resourceyang tersisa ketika onDestroy() dipanggil. Contohnya, jika ada sebuah thread yang berjalan pada latar untuk mengunduh data dari jaringan, maka thread tersebut akan dibuat pada onCreate() dan dihentikan pada onDestroy(). b. Visible Lifetime, ketika activity tampak di layar, terjadi pada saat method onStart() dipanggil hingga onStop(). Pada masa ini, pengguna dapat melihat activity di layar, walaupun tidak muncul di permukaan dan berinteraksi dengan pengguna. Di antara kedua method ini, resource yang dibutuhkan akan tetap aktif untuk menunjukkan activity kepadapengguna. Contohnya, Dasar Pemrograman Android anda dapat mendaftarkan BroadcastReceiver pada Page 106 onStart() untuk memantau perubahan yang berdampak pada UI (Pengguna Interface), dan melepaskannya pada onStop() ketika anda ingin menghilangkan tampilan activity dari layar. Method onStart() dan onStop() dapat dipanggil berkali-kali, tergantung pada situasi ketika activity ingin ditampilkan atau tidak. c. Foreground Lifetime, masa hidup di permukaan. Terjadi ketika method onResume() dipanggil hingga method onPause(). Selama periode ini, activity beriteraksi dengan pengguna dan terletak di atas semua activity yang lain. Sebuah activity dapat bertransisi antara kondisi resumed dan pause-contohnya, onPause() dipanggil ketika perangkat diatur pada kondisi sleep atau ketika activity baru dimulai. Dan onResume() dipanggil ketika hasil dari activity muncul atau ada intent baru yang dikirimkan. Oleh karena itu, kode pada kedua method ini sangatlah ringan. Diagram berikut ini akan menggambarkan loop dan path yang dilalui activity ketika berpindah kondisi. Bentuk oval yang berwarna merupakan kondisi umum activity. Bentuk persegi panjang menggambarkan pemanggilan method yang dapat anda panggil untuk melaksanakan operasi ketika activity melakukan transisi kondisi. Dasar Pemrograman Android Page 107 Gambar 3.1 Siklus Hidup Activity. Tabel berikut ini akan menunjukkan method tersebut secara rinci dan menjelaskan lokasi method di dalam siklus hidup activity. Method onCreate() Deskripsi Dipanggil ketika activity pertama dibuat. Dapat dihentikan? Tidak Selanjutnya onStart() Ini adalah masa ketika anda harus Dasar Pemrograman Android Page 108 menentukan aturan normal yang akan diberlakukan-membuatviews, membuat daftar data, dan sebagainya. Method ini dilewatkan kumpulan obyek dari activity sebelumnya, jika kondisi tersebut ingin dipertahankan, maka akan selalu diikuti dengan onStart(). onRestart() Dipanggil ketika activity akan dihentikan, Tidak onStart() Tidak onResume() sebelum dijalankan kembali. Selalu diikuti dengan onStart(). onStart() Dipanggil sebelum activity dapat dilihat atau oleh pengguna. Diikuti dengan onResume() onStop() jika activityakan muncul di permukaan atau onStop() jika akan disembunyikan di latar. onResume() Dipanggil sesaat sebelum activity mulai Tidak onPause() Ya onResume() berinteraksi dengan pengguna. Pada masa ini, activity akan terletak pada posisi atas di susunan activity, menunggu input dari pengguna. Selalu diikuti dengan onPause(). onPause() Dipanggil ketika sistem akan memulai activity yang lain. Method ini digunakan khusus untuk menjalankan perubahan data atau onStop() yang belum disimpan, menghentikan animasi dan hal lain yang akan memakan sumber CPU, dan sebagainya. Harus dilakukan dalam waktu sesingkat mungkin, karena activity berikutnya tidak akan dijalankan sebelum activity tersebut kembali. Akan diikuti dengan Dasar Pemrograman Android Page 109 onResume() jika activity kembali ke permukaan atau onStop() jika activity ingin disembunyikan. onStop() Dipanggil ketika activity tidak dapat dilihat Ya onRestart() oleh pengguna. Hal ini dapat terjadi ketika atau activity dihentikan, atau karena ada activity onDestroy() lain (yang telah berjalan atau yang baru saja diaktifkan) yang berjalan dan menutupi activity tersebut. Diikuti oleh onRestart() jika activity kembali berinteraksi dengan pengguna dan onDestroy() jika activity telah selesai. onDestroy() Dipanggil sebelum activity dihentikan. Ya Tidak ada Method ini adalah panggilan terakhir yang diterima oleh activity. Dapat dipanggil karena activity telah selesai atau (memanggil finish()),atau karena sistem menonaktifkan instance activity ini untuk sementara untuk menghemat tempat. Anda dapat membedakan antara dua skenario ini dengan menggunakan method isFinishing(). Perlu diketahui bahwa kolom “Dapat Dihentikan” di atas menunjukkan apakah sistem dapat menghentikan proses dari setiap activity pada waktu kapanpun nilai method dikembalikan, tanpa mengeksekusi baris lain di dalam activity. Tiga method (onPause(), onStop() dan onDestroy()) dinyatakan “Ya”. Karena onPause() disebutkan pertama kali di antara ketiganya, maka hanya method itu yang dijamin akan dipanggil sebelum proses dimatikan. Namun tidak dengan onStop() dan onDestroy(). Oleh karena itu, sebaiknya menggunakan onPause() untuk menulis data persistence seperti data yang disunting oleh pengguna pada storage. Dasar Pemrograman Android Page 110 Method yang dinyatakan “Tidak” pada kolom “Dapat Dihentikan” menandakan bahwa proses tidak dapat mematikan activity sejak dipanggil. Misalnya pada waktuonPause() hingga kembalionResume() , maka activity tidak dapat dihentikan hingga methodonPause() dipanggil kembali. Jadi, walaupun secara teknis sebuah activity “tidak dapat dihentikan”, maka dengan definisi ini, tetap dapat dimatikan oleh sistem, namun hal itu hanya dapat terjadi pada kondisi dan situasi tertentu ketika perangkat tidak lagi mempunyai sumber daya yang memadai. 3.6.2 Menyimpan activity state Ketika sistem menghentikan sebuah activity untuk menghemat memori, mungkin saja pengguna ingin kembali ke activity sebelumnya dan mendapatkan activity dalam kondisi yang sama seperti sebelumnya. Untuk menjaga kondisi agar tampak sama seperti sebelum dihentikan, maka dapat mengimplementasi method onSaveInstanceState() untuk activity tersebut. Android akan memanggil method ini sebelum activity dihentikan. Pada saat sebelum method onPause() dipanggil, Android akan melewatkan method object Bundle yang dapat menyimpan kondisi dinamis dari activity sebagai name-value pairs. Ketika activity dijalankan kembali, maka Bundle akan dilewatkan onRestoreInstanceState() pada dua method, yaitu onCreate() dan method yang dipanggil setelah method onStart(). Sehingga keduanya atau salah satu dari method tersebut dapat mengembalikan kondisi seperti sedia kala. Tidak seperti method onPause() dan method yang dijelaskan sebelumnya, method onSaveInstanceState() Kedua method dan onRestoreInstanceState() bukanlah method siklus hidup. ini onSaveInstanceState() selalu dipanggil. Contohnya, Android memanggil sebelum activity dimatikan oleh sistem, namun pada situasi ini masih memungkinkan untuk memanggil onSaveInstanceState() ketika instance dinonaktifkan oleh aksi dari pengguna (seperti menyentuh tombol BACK). Dalam hal ini, pengguna dianggap tidak akan kembali ke activity, sehingga tidak ada alasan untuk menyimpan kondisi tersebut. Karena onSaveInstanceState() tidak selalu dipanggil, maka menggunakannya hanya untuk menyimpan kondisi sementara dari activity, bukan data yang bersifat permanen. Untuk menyimpan data permanen, sebaiknya gunakan onPause(). 3.6.3 Koordinasi Activity Dasar Pemrograman Android Page 111 Ketika sebuah activity memicu activity lainnya, maka kedua activity tersebut akan mengalami transisi siklus hidup. Ketika salah satunya berubah status menjadi pause atau stop, maka yang lainnya akan dijalankan. Pada saat tertentu, ada kemungkinan dibutuhkan koordinasi antara activity ini. Urutan pemanggilan siklus hidup ini telah ditentungkan, khususnya ketika dua activity berada di dalam proses yang sama: a. Method onPause() dari activity yang sedang berjalan akan dipanggil. b. Method onCreate(), onStart() dan onResume() dari activity yang baru saja dijalankan akan dipanggil. c. Kemudian jika activity yang baru saja dimulai ingin disembunyikan, maka method onStop() di dalamnya akan dipanggil 3.6.4 Siklus Hidup Service Service dapat digunakan dengan dua cara: a. Service dapat dimulai dan diizinkan untuk berjalan sampai sesuatu menghentikannya atau tiba saatnya untuk non aktif. Dalam mode ini, service akan dimulai dengan cara memanggil Context.startService() dan dihentikan dengan memanggil Context.stopService(). Service dapat berhenti secara otomatis dengan memanggil Service.stopSelf() atau Service.stopSelfResult(). stopService() Hanya membutuhkan satu kali panggilan untuk menghentikan service, walaupun beberapa kali memanggil method startService(). b. Service dapat dioperasikan secara programming dengan menggunakan interface. Client membuat koneksi ke objectservice dan menggunakan koneksi tersebut untuk memanggil service. Koneksi dibuka dengan cara memanggil Context.bindService() dan ditutup dengan method Context.unbindService(). Hal ini dapat dilakukan oleh banyak client pada service yang sama. Jika service belum diluncurkan, maka bindService() dapat meluncurkannya. Kedua mode ini tidak terpisah secara keseluruhan. Koneksi dapat dilakukan service yang dijalankan dengan startService(). Contohnya, musik yang dimainkan pada latar dapat dijalankan dengan cara memanggil startService() yang akan menentukan sebuah intent object untuk memainkan musik. Hanya saja, jika pengguna ingin mengendalikan music player atau mendapatkan informasi tentang lagu yang sedang dimainkan, apakah activity akan membuat Dasar Pemrograman Android Page 112 koneksi dengan service dengan memanggil bindService(). Pada kasus seperti ini, stopService() Seperti tidak akan menghentikan service sampai koneksi sebelumnya ditutup. activity, service juga mempunyai method siklus hidup yang dapat diimplementasikan untuk memantau perubahan statusnya. Tetapi service hanya mempunyai tiga public method: a. voidonCreate() b. void onStart(Intent intent) c. void onDestroy(). Dengan mengimplementasikan ketiga method ini, dapat dipantau dua nested loop dari siklus hidup service, yaitu: 1. Entire Lifetime, masa hidup service adalah pada periode ketika method onCreate() dipanggil hingga kemudian semua resource dilepaskan dengan memanggil onDestroy(). Serupa dengan activity, service juga menetapkan aturan awal pada pemanggilan onCreate(), dan melepaskan semua resource pada onDestroy(). Misalnya, service yang memainkan musik pada background dapat membuat thread ketika musik akan dimainkan di dalam method onCreate(),dan akan menghentikan thread pada onDestroy(). 2. Active Lifetime, masa hidup aktif sebuah service akan dimulai dengan memanggil onStart(). Method ini akan membuat intent object yang akan dilewatkan di method startService(). Kemudian musik akan membuka intent untuk menentukan lagu yang akan diputar dan memainkannya. 3. Tidak ada pemanggilan yang sama ketika service dihentikan, tidak ada method onStop(). Method onCreate() dan onDestroy() dipanggil untuk semua service, baik dimulai oleh Context.startService() maupun Context.bindService(). Namun, onStart() hanya akan dipanggil untuk service yang dimulai oleh method startService(). 4. Jika sebuah service mengizinkan service lain untuk mengadakan koneksi, maka method tambahan untuk diimplementasi adalah sebagai berikut: a. IBinder onBind (Intent intent) b. boolean onUnbind (Intent intent) c. void onRebind (Intent intent) Dasar Pemrograman Android Page 113 Pemanggilan balik onBind() ditangani oleh intent object yang dilewatkan ke bindService. Dan onUnbind() ditangani oleh intent yang dilewatkan di unbindService(). Jika service mengizinkan koneksi tersebut, maka onBind() akan mengembalikan jalur komunikasi yang digunakan client untuk berinteraksi dengan service. Method onUnbind() dapat meminta onRebind() untuk dipanggil jika ada client baru yang ingin membuka koneksi dengan service tersebut. Diagram berikut ini menggambarkan metode pemanggilan balik sebuah service. Walaupun service yang dibuat melalui startService dengan service yang dibuat oleh bindService() dipisahkan. Ingatlah bahwa semua service, dapat mengizinkan client untuk menjalin koneksi, sehingga service apapun dapat menerima panggilan onBind() dan onUnbind(). Dasar Pemrograman Android Page 114 Gambar 3.2 Siklus Hidup Service. 3.6.5 Siklus Hidup Broadcast Receiver Sebuah broadcast receiver mempunyai method pemanggilan balik sebagai berikut: void onReceive (Context curContext, Intent broadcastMsg) Ketika sebuah broadcast message diterima oleh receiver, Android memanggil method onReceive() dan melewatkannya ke dalam intent object yang berisi pesan. Broadcast receiver hanya aktif ketika sedang menjalankan method ini. Proses dengan broadcast receiver yang aktif tidak akan dimatikan. Namun, proses dengan komponen yang tidak aktif dapat dimatikan oleh sistem setiap saat, ketika memori yang digunakannya sedang dibutuhkan oleh proses lainnya. Hal ini menimbulkan masalah ketika respon ke broadcast message adalahmemakan waktu dan untuk itu perlu dilakukan sesuatu pada thread yang terpisah, jauh dari thread utama dimana komponen lain dari interface pengguna sedang berjalan. Jika onReceive() membuat sebuah thread baru dan kembali, maka proses keseluruhan, termasuk thread yang baru dibuat akan dinilai tidak dalam keadaan aktif (kecuali ada komponen aplikasi lain yang sedang aktif di dalam proses tersebut) dan dapat dimatikankapan saja. Solusi dari masalah ini adalah mengatur onReceive() untuk memulai service baru yang akan menangani pekerjaan tersebut, sehingga sistem akan tahu bahwa masih ada pekerjaan aktif yang masih dilakukan di dalam proses. 3.6.6 Proses dan Siklus Hidup Sistem Android akan menjaga proses aplikasi selama mungkin, namun pada akhirnya sistem harus menghentikan proses yang terdahulu ketika low memory. Untuk menentukan proses mana yang harus dipertahankan, Android menempatkan setiap proses ke dalam “susunan prioritas” berdasarkan komponen yang sedang berjalan di dalamnya dan kondisi dari setiap komponen. Proses dengan tingkat kepentingan paling rendah akan dimatikan lebih dulu, kemudian kedua paling rendah, dan selanjutnya. Hirarki tersebut terdiri dari 5 tingkat. Berikut adalah daftar proses berdasarkan kepentingannya: Dasar Pemrograman Android Page 115 1. Foreground process, proses yang berjalan di permukaan. Merupakan proses yang ada di tingkat paling atas, menangani apa yang sedang dilakukan oleh pengguna. Proses yang ada di permukaan adalah proses dengan kondisi sebagai berikut: a. Menjalankan activity yang berinteraksi dengan pengguna (method onResume() obyek activity telah dipanggil ). b. Menjalankan service yang menangani activity yang berinteraksi dengan pengguna. c. Mempunyai obyek yang akan mengeksekusi pemanggilan kembali siklus hidupnya (onCreate(), onStart() atau onDestroy() ). d. Mempunyai obyek BroadcastReceiver yang akan mengeksekusi method onReceive(). Beberapa Foreground process akan dijalankan pada satu waktu. Proses tersebut akan dimatikan ketika lowmemory sehingga tidak semua proses dapat dijalankan pada saat yang bersamaan. Umumnya ketika sampai pada tahap itu, perangkat akan melakukan pembagian memori (memory paging) yang akan menentukan proses mana yang akan dimatikan dan menjaga agar antar muka tetap responsif. 2. Visible Process, proses yang dapat terlihat di layar. Proses ini tidak mempunyai komponen pada foreground, tapi masih dapat mempengaruhi apa yang pengguna lihat di layar. Ciri dari proses ini adalah sebagai berikut: a. Menjalankan aktifitas yang tidak tampil di permukaan, namun masih dapat terlihat oleh penguna (method onPause() telah dipanggil). Hal ini dapat terjadi, misalnya, jika activity foreground adalah sebuah dialog yang masih memperlihatkan activity di belakangnya. b. Menjalankan service yang terikat pada activity yang masih dapat terlihat Visible activity dianggap sebagai activity yang penting dan tidak akan dimatikan kecuali memori sedang dibutuhkan untuk menjalankan proses yang ada di permukaan. 3. Service process, merupakan proses yang menjalankan service yang telah dimulai dengan memanggil method startService() dan tidak berpindah ke dua kategori service di atasnya. Walaupun proses service tidak terikat secara langsung kepada apapun yang dilihat oleh pengguna. Contohnya memainkan musik MP3 pada latar atau mengunduh data dari jaringan, sehingga sistem akan tetap menjalankannya selama ada memori yang tersedia dan tidak mengganggu proses foreground dan visible. Dasar Pemrograman Android Page 116 4. Background Process, merupakan activity yang dijalankan tanpa terlihat oleh pengguna dan berjalan pada background (object method onStop() telah dipanggil). Proses ini tidak berdampak langsung pada experience pengguna, dan dapat dimatikan kapan saja jika memori sedang dibutuhkan oleh proses foreground, visible, atau service. Biasanya ada banyak proses background yang dijalankan, sehingga diletakkan di daftar LRU (Least Recently Used). Daftar ini digunakan untuk memastikan bahwa proses dengan activity tersebut adalah hal yang baru saja dilihat oleh pengguna dan activity terakhir yang akan dimatikan. Jika sebuah activity mengimplementasi method siklus hidupnya dengan tepat dan menangkap kondisi yang sedang berjalan, maka saat prosesnya dimatikan tidak akan mengganggu experiencepengguna. 5. Empty Process, merupakan proses yang tidak menjalankan komponen aplikasi yang sedang aktif. Proses ini tetap dijalankan sebagai cache (media penyimpanan sementara) untuk meningkatkan performa aplikasi ketika akan dijalankan kembali. Sistem akan mematikan proses ini untuk menjaga keseimbangan sumber daya keseluruhan antara proses cache dan cache di kernel. Android membuat daftar prioritas proses, berdasarkan atas kepentingan komponen aktif yang sedang berjalan di dalam proses. Contohnya, jika sebuah proses menjalankan service dan visible, maka proses tersebut akan diberikan peringkat sebagai proses visible, bukan proses service. Sebagai tambahan, peringkat proses dapat bertambah jika ada proses lain yang bergantung kepadanya. Sebuah proses yang melayani proses yang lain tidak akan diletakkan pada peringkat lebih rendah dari proses lain yang dilayaninya. Misalnya, jika content provider di dalam proses A sedang melayani client pada proses B, atau jika service di dalam proses A terkait pada komponen di proses B, maka proses A akan selalu dianggap sama pentingnya dengan proses B. Karena proses yang menjalankan service akan diletakkan pada peringkat yang lebih tinggi daripada backgroundactivity. Sebuah activity yang mengawali operasi yang membutuhkan waktu lama akan memulai service untuk menjalankannya, tidak dengan membuat thread baru, khususnya jika operasi ini akan dimatikan paling akhir di dalam activity. Contohnya, memainkan musik pada latar atau mengunggah gambar yang baru saja ditangkap kamera ke situs. Dengan menggunakan service akan menjamin bahwa operasi ini akan mendapatkan prioritas, apapun Dasar Pemrograman Android Page 117 yang akan terjadi di dalam activity. sebagaimana dijelaskan pada bagian Siklus Hidup Broadcast Receiver sebelumnya, maka dengan alasan inilah broadcast receiver sebaiknya menggunakna service dibandingkan dengan menjalankan operasinya di dalam thread. Dasar Pemrograman Android Page 118 3.7 Widget View Selanjutnya, akan dibahas penggunaan komponen-komponen yang ada di Android. Pada bagian ini akan dibahas mengenai widget view yaitu Text Controls, Button, CheckBox, RadioButton, Rating Bar, List, Grid, Date, Time, Gallery dan Spinner. 3.7.1 TextControl Text control adalah tipe pertama dari komponen Android yang akan dipelajari. Pada bagian ini akan dibahas tentang pengunaan TextView, EditText, AutoCompleteTextView, dan MultiCompleteTextView. 3.7.2 TextView Komponen TextView ini dapat menampilkan tulisan di layar tetapi pengguna tidak dapat mengubah tulisan tersebut. Perlu diketahui bahwa TextView juga dapat membuat autoLink terhadap URL. Jadi apabila pengguna menekan TextView, maka sistem akan merujuk pada halaman web dari URL tersebut dengan menggunakan class android.text.util.Linkfy. Berikut ini adalah potongan kode definisi pebuatan TextView dalam bentuk XML: publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv=new TextView(this); tv.setText("SEAMEO REGIONAL OPEN LEARNING CENTRE " + " Komplek Universitas Terbuka " + " Jl. Cabe Raya,Pondok Cabe Pamulang 15418 " + " PO BOX 59/CPA,Ciputat 15401 Jakarta - INDONESIA " + " Tel : (62-21)7422184 , 7423725 , 7424154 " + " Fax : (62-21)7422276 " + " Website : http://www.seamolec.org " + " e-mail : [email protected] " ); Linkify.addLinks(tv, Linkify.ALL); setContentView(tv); } Hasil potongan kode di atas adalah sebagai berikut: Dasar Pemrograman Android Page 119 Gambar 3.3 Tampilan penggunaan TextView. Ketika link URL dan link telepon ditekan hasilnya seperti gambar berikut: Gambar 3.4 Tampilan link URL dan telepon ketika di tekan pada TextView. Pada contoh ini, method addLinks() dipanggil dari Linkify. Linkify membuat link dari teks yang terlihat seperti nomor handphone, email address, web URL, ataupun map address. 3.7.3 EditText EditText merupakan subclass dari TextView. EditText dapat digunakan untuk mengubah teks dan juga dapat digunakan untuk memasukkan input berupa angka saja atau membuat kata kunci. EditText et =new EditText(this); et.setText("Ini merupakan salah satu contoh dari EditText"); Dasar Pemrograman Android Page 120 Spannable spn = et.getText(); spn.setSpan(new BackgroundColorSpan(Color.RED), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spn.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC) , 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); setContentView(et); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.5 Tampilan EditText. Dari contoh diatas, isi dari EditText juga dapat diubah dengan menggunakan object Spannable. Teks juga dapat dibuat menjadi bolddan italics, atau diberikan warna background menjadi merah. Penyuntingan tulisan dengan menggunakan EditText ini juga tidak dibatasi seperti menggunakan superscript, subscript strikethrough, dan sebagainya. 3.7.4 AutoCompleteTextView AutoCompleteTextView merupakan TextView dengan fungsi auto-complete. Ketika pengguna menyentuh huruf, maka akan muncul pilihan menu yang dapat dipilih. LinearLayout ly=new LinearLayout(this); TextView txt=new TextView(this); Dasar Pemrograman Android Page 121 txt.setText("Nama kota di Indonesia : "); ly.addView(txt); AutoCompleteTextView actv = new AutoCompleteTextView(this); ArrayAdapter<String> aa = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,new String[] {"Cimahi", "Bandung", "Jakarta", "Surabaya", "Bali", "Semarang","Balikpapan"}); actv.setAdapter(aa); actv.setWidth(500); actv.setHeight(50); ly.addView(actv); setContentView(ly); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.6 Tampilan AutoCompleteTextView. Pada kode diatas, AutoCompleteTextView menunjukkan daftar kota kepada pengguna. Sebagai contoh, jika pengguna mengetik kata“ci”, komponen menunjukkan kepada Cimahi. Dan apabila pengguna mengetik kata“ba”,maka akan muncul Bandung, Bali, Balikpapan dan lainnya. 3.7.5 MultiAutoCompleteTextView Cara menggunakan MultiAutoCompleteTextView sama seperti AutoCompleteTextView. Perbedaannya adalah dapat memilih lebih dari satu kata dengan menggunakan tanda koma. Sebagai contoh, ketika mengetikkata “ci”dan memilih Cimahi. Setelah itu diberi tanda koma, kemudian mengetikkan kata ”ba”maka akan muncul pilihan Bandung, Bali, Balikpapan, dst. LinearLayout ly=new LinearLayout(this); Dasar Pemrograman Android Page 122 TextView txt=new TextView(this); txt.setText("Nama kota di Indonesia : "); ly.addView(txt); MultiAutoCompleteTextView mactv = new MultiAutoCompleteTextView(this); ArrayAdapter<String> aa2 = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,new String[] {"Cimahi", "Bandung", "Jakarta", "Surabaya", "Bali", "Semarang","Balikpapan"}); mactv.setAdapter(aa2); mactv.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer()); mactv.setWidth(500); mactv.setHeight(50); ly.addView(mactv); setContentView(ly); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.7 Tampilan MultiAutoCompleteTextView. 3.7.6 Button Pada bagian ini, akan dibahas empat jenis button yang sering digunakan dalam mengembangkan aplikasi di Android. Button tersebut antara lain Basic Button, Image Button, Toggle Button dan Custom Button. 3.7.6.1 Basic Button Button yang paling dasar di Android adalah android.widget.Button.Class ini hanya dapat menangani event ketika buttondi tekan dengan menggunakan OnClickListener. Berikut ini adalah potongan kode definisi pebuatan button dalam bentuk XML: Dasar Pemrograman Android Page 123 <Buttonandroid:id="@+id/ccbtn1" android:text="Basic Button" android:typeface="serif" android:textStyle="bold" android:layout_width="fill_parent" android:layout_height="wrap_content"/> Berikut ini adalah potongan kode pemanggilan button menggunakan code Java: Button btn = (Button)this.findViewById(R.id.ccbtn1); btn.setOnClickListener(new OnClickListener(){ publicvoid onClick(View v){ finish(); } }); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.8 Tampilan Basic Button. Kode diatas menjelaskan tentang bagaimana event ketika button ditekan. Event tersebut didaftarkan pada method setOnClickListener() dari ClassOnClickListener. Didalam kode, listener dibuat untuk menangani event ketika button ditekan. Ketika button ditekan method OnClick() otomatis langsung dieksekusi. 3.7.6.2 Image Button Android mendukung image button melaluiandroid.widget.ImageButton.Penggunaan image button hampir sama dengan basic button. Berikut adalah potongan kode menggunakan layout XML: Dasar Pemrograman Android Page 124 <ImageButtonandroid:id="@+id/imageBtn" android:layout_width="wrap_content" android:layout_height="wrap_content"/> Image dari button juga dapat dibuat secara dinamis melalui method setImageResource() atau dengan memodifikasi file XML layout dengan menambahkan android: src yang merujuk pada ID image seprti yang terlihat pada potongan kode berikut. <ImageButtonandroid:id="@+id/imageBtn" android:src="@drawable/btnImage" android:layout_width="wrap_content" android:layout_height="wrap_content" /> Berikut ini adalah potongan kode pemanggilan image button menggunakan kode Java: ImageButton btn = (ImageButton)this.findViewById(R.id.imageBtn); btn.setImageResource(R.drawable.icon); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.9 Tampilan Image Button. 3.7.6.3 Toggle Button ToggleButton ini seperti check box atau radio button. Button ini mengarah pada On dan Off. ToggleButton akan menampikan green-bar pada keadaan On dan grayed-outbar pada keadaan Off. Selain itu juga, button akan bertuliskan On pada saat keadaan On dan bertuliskan Off pada saat keadaan Off. <ToggleButtonandroid:id="@+id/cctglBtn" android:layout_width="wrap_content" Dasar Pemrograman Android Page 125 android:layout_height="wrap_content" android:text="Toggle Button"/> Selain itu, tulisan On-Off tersebut dapat diubah dengan android:textOn dan android:textOff seperti yang terlihat pada potongan kode berikut. <ToggleButtonandroid:id="@+id/cctglBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textOn="Run" android:textOff="Stop" android:text="Toggle Button"/> Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.10 Tampilan Toggle Button. 3.7.6.4 Custom Button Pada bagian ini, akan dijelaskan bagaimana membuatbuttondengan menggunakan custom image, bukan menggunakan teks. Pembuatan custom button menggunakan Buttonwidget dan sebuah file XML yang mendefinisikan tiga image yang berbeda untuk digunakan pada button yang berbeda. Gambar 3.11 Tampilan image untuk Custom Button. Berikut dapat dilihat potongan kode pembuatan Custom Button pada file XML: <?xmlversion="1.0"encoding="utf-8"?> Dasar Pemrograman Android Page 126 <selectorxmlns:android="http://schemas.android.com/apk/res/android"> <itemandroid:drawable="@drawable/android_pressed" android:state_pressed="true" /> <itemandroid:drawable="@drawable/android_focused" android:state_focused="true" /> <itemandroid:drawable="@drawable/android_normal" /> </selector> Source kode di atas mendefinisikan sebuah single drawable resource yang berada pada drawable dengan dalam kasus ini nama file-nya adalah android_button.xml yang akan mengganti image berdasarkan status yang berlaku pada saat button ditekan. <item> pertama definisasikan android_pressed.png sebagai image pada saat button ditekan (diaktifkan); <item> kedua mendefinisikan android_focused.png sebagai image pada saat button di-highlight; dan <item> yang ketiga mendefinisasikan android_normal.png sebagai image pada saat tidak sedang aktif. File XML ini merepresentasikan sebuah single drawable resource dan pada saat button ditekan, image akan ditampilkan berdasarkan state yang telah diatur pada konfigurasi di atas. Setelah selesai mendefinisikan selector di atas, selajutnya selector tersebut akan di panggil dalam layout file XML yang akan ditampilkan. <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:background="@drawable/android_button"/> android:background menspesifikasikan drawableresource mana yang akan digunakan sebagai background (dimana pada saat disimpan dalam/res/drawable/android.xml, direferensikan sebagai @drawable/android). Ini menggantikan normal backgroundimage yang digunakan sebagai button pada system ini. Dasar Pemrograman Android Page 127 Gambar 3.12 Tampilan image untuk Custom Button. 3.7.6.5 CheckBox CheckBox memiliki dua keadaan yaitu On dan Off sama seperti ToggleButton. Dalam pembuatannya di Android, dapat menggunakan class android.widget.CheckBox. Berikut adalah potongan kode dalam bentuk XML. <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Makanan kesukaan :"> </TextView> <CheckBoxandroid:text="Nasi Goreng" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBoxandroid:text="Nasi Pecel" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBoxandroid:text="Nasi Uduk" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBoxandroid:text="Nasi Kuning" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> Dasar Pemrograman Android Page 128 Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.13 Tampilan CheckBox. Event dapat dimanipulasi dengan memanggil method setOnCheckedChangeListener() dengan mengimplementasikan interface OnCheckedChangeListener kemudian dilanjutkan dengan meng-override method onCheckedChanged(). 3.7.7 RadioButton RadioButton memberikan pilihan kepada pengguna, namun pengguna hanya dapat memilih satu item saja. Untuk membuat group dari RadioButton, pertama buat RadioGroup kemudian tambahkan RadioButton ke dalam group. <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Makanan kesukaan :"></TextView> <RadioGroupandroid:id="@+id/rBtnGrp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <RadioButtonandroid:id="@+id/gorengRBtn"android:text="Nasi Goreng" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <RadioButtonandroid:id="@+id/udukRBtn"android:text="Nasi Uduk" android:layout_width="wrap_content" Dasar Pemrograman Android Page 129 android:layout_height="wrap_content"/> <RadioButtonandroid:id="@+id/pecelRBtn"android:text="Nasi Pecel" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RadioGroup> </LinearLayout> Berikut ini adalah potongan kode pemanggilan RadioGroup menggunakan kode Java: RadioGroup rdgrp = (RadioGroup)findViewById(R.id.rBtnGrp); RadioButton newRadioBtn = new RadioButton(this); newRadioBtn.setText("Nasi Kuning"); rdgrp.addView(newRadioBtn); newRadioBtn.setChecked(true); Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.14 Tampilan RadioButton. 3.7.8 RatingBar Pada bagian ini, akan dijelaskan bagaimana membuat sebuah widget yang memperbolehkan pengguna untuk menambahkan rating, dengan widget RatingBar. Berikut adalah potongan kode dalam bentuk XML. <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"> Dasar Pemrograman Android Page 130 <TextViewandroid:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nilai anda : "/> <RatingBarandroid:id="@+id/ratingbar" android:layout_width="wrap_content" android:layout_height="wrap_content"android:numStars="5" android:stepSize="1.0"/> </LinearLayout> Attribut android:numStars mendefinisikan berapa banyak “bintang” yang akan ditampilkan pada ratingbar. Atribut android:stepSize mendefinisikan potongan untuk setiap bintang (contoh, sebuah nilai dari 0.5 akan menampilkan sebuah bintang yang terpotong setengah). Berikut ini adalah potongan kode pemanggilan RatingBar menggunakan kode Java: RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar); ratingbar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() { publicvoid onRatingChanged(RatingBar ratingBar, float rating, boolean fromPengguna) { Toast.makeText(Main.this, “Rating anda: " + rating, Toast.LENGTH_SHORT).show(); } }); Kode di atas menerima widget RatingBardari layout menggunakan findViewById(int) kemudian akan menampilkan sebuah ratingbar RatingBar.OnRatingBarChangeListener.onRatingChanged(). dengan memanggil Setelah event terjadi ketikan menekan tombol rating maka akan muncul sebuah Toast untuk menampilkan rating. Hasil potongan kode di atas adalah sebagai berikut: Dasar Pemrograman Android Page 131 Gambar 3.15 Tampilan RatingBar. 3.7.9 ListView ListView berfungsi untuk menampilkan list dari sekumpulan item secara vertikal. Pada umumnya, ListView ditulis pada Activity yang meng-extend Android.app.ListActivity. <?xmlversion="1.0"encoding="utf-8"?> <TextViewxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"android:layout_height="fill_parent" android:padding="10dp" android:textSize="16sp"> </TextView> Berikut ini adalah potongan kode pemanggilan ListView menggunakan kode Java: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] nama = { "Rinal", "Iman", "Andzar", "Regi", "Metra", "Dexwan", "Esha", "Slamet", "Ade" }; setListAdapter(new ArrayAdapter<String>(this, R.layout.main, nama)); ListView lv = getListView(); lv.setTextFilterEnabled(true); lv.setOnItemClickListener(null); } public void onItemClick(AdapterView<?> arg0, View arg1, Dasar Pemrograman Android Page 132 int arg2, long arg3) { TextView textView = (TextView) arg1; Toast.makeText(getApplicationContext(),textView.getText(), Toast.LENGTH_SHORT).show(); } Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.16 Tampilan ListView. 3.7.10 GridView Android memiliki GridView yang dapat menampilkan data dalam bentuk grid. Data yang ditampilkan dapat berupa teks, gambar, dan lain-lain. GridView menampilkan informasi berupa grid. Berikut adalah potongan kode dalam bentuk XML. <?xmlversion="1.0"encoding="utf-8"?> <GridViewxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dataGrid" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10px" android:verticalSpacing="10px" Dasar Pemrograman Android Page 133 android:horizontalSpacing="10px" android:numColumns="auto_fit" android:columnWidth="100px" android:stretchMode="columnWidth" android:gravity="center"/> Berikut ini adalah potongan kode pemanggilan GridView menggunakan kode Java: publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); GridView gv = (GridView) this.findViewById(R.id.dataGrid); String kota[] = { "Cimahi", "Bandung", "Jakarta", "Denpasar", "Surabaya", "Malang", "Semarang", "Pontianak", "Medan", "Aceh", "Sidoarjo", "Batam", "Tangerang" }; gv.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, kota)); gv.setOnItemClickListener(new OnItemClickListener() { publicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3){ Toast.makeText(Main.this, "" + arg2, Toast.LENGTH_SHORT).show(); } }); } Hasil potongan kode di atas adalah sebagai berikut: Dasar Pemrograman Android Page 134 Gambar 3.17 Tampilan GridView. 3.7.11 Date and Time Pada bagian ini, akan dibahas tentang widget DatePicker, TimePicker, AnalogClock, dan DigitalClock. a. DatePicker dan TimePicker DatePicker merupakan widget yang digunakan untuk mengatur tanggal (hari, bulan, tahun), sedangkan TimePicker untuk mengatur waktu (jam dan menit). Selain dalam bentuk widget ada pula dalam bentuk dialog dengan fungsi yang sama yaitu DatePickerDialog dan TimePickerDialog. DatePicker dapat diatur tanggalnya dalam bentuk tahun, bulan , dan hari. Nilai (values) bulan dari widget DatePicker dimulai dari 0 untuk Januari sampai 11 untuk bulan Desember. Widget tersebut pun memiliki fungsi objek callback (onDateChangedListener atau onDateSetListener) yang berfungsi untuk memberi informasi tanggal yang dipilih atau diatur oleh pengguna. Seperti halnya DatePicker, TimePicker pun dapat diatur jamnya dalam bentuk menit (nilainya 0~59) dan jam (nilainya 0~23). Adapun indikasi saat menggunakan TimePicker adalah mode 12 jam atau mode 24 jam. TimePicker pun memiliki fungsi objek callback Dasar Pemrograman Android Page 135 (onTimeChangedListener atau onTimeSetListener) yang berfungsi untuk memberi informasi waktu dalam bentuk jam dan menit. Berikut adalah potongan kode dalam bentuk XML. main.xml <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"> <DatePickerandroid:id="@+id/datePicker" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TimePickerandroid:id="@+id/timePicker" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> Berikut ini adalah potongan kode pemanggilan DatePicker dan TimePicker menggunakan kode Java: publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); DatePicker dp = (DatePicker) this.findViewById(R.id.datePicker); dp.init(1992, 9, 19, null); TimePicker tp = (TimePicker) this.findViewById(R.id.timePicker); tp.setIs24HourView(true); tp.setCurrentHour(new Integer(10)); tp.setCurrentMinute(new Integer(10)); } Hasil potongan kode di atas adalah sebagai berikut: Dasar Pemrograman Android Page 136 Gambar 3.18 Tampilan DatePicker dan TimePicker. Untuk memodifikasi tampilan DatePicker dan TimePicker menjadi lebih kompleks, dapat menggunakan kode seperti di bawah ini. main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/lblDateAndTime" android:layout_width="fill_parent" android:layout_height="47px" android:background="#ff000099" android:textStyle="bold" > </TextView> <Button android:id="@+id/buttonDate" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="set Date" /> <Button android:id="@+id/buttonTime" android:layout_width="fill_parent" Dasar Pemrograman Android Page 137 android:layout_height="wrap_content" android:text="set Time" /> </LinearLayout> DateandTimeActivity.java package coba.latihan; import java.text.DateFormat; import java.util.Calendar; import import import import import import import import import import android.app.Activity; android.app.DatePickerDialog; android.app.TimePickerDialog; android.os.Bundle; android.view.View; android.view.View.OnClickListener; android.widget.Button; android.widget.DatePicker; android.widget.TextView; android.widget.TimePicker; public class DateandTimeActivity extends Activity { /** Called when the activity is first created. */ DateFormat fmtDateAndTime = DateFormat.getDateTimeInstance(); TextView lblDateAndTime; Calendar myCalendar = Calendar.getInstance(); DatePickerDialog.OnDateSetListener d = new DatePickerDialog.OnDateSetListener(){ @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { // TODO Auto-generated method stub myCalendar.set(Calendar.YEAR, year); myCalendar.set(Calendar.MONTH, monthOfYear); myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); updatelabel(); } }; TimePickerDialog.OnTimeSetListener t = new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { Dasar Pemrograman Android Page 138 // TODO Auto-generated method stub myCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay); myCalendar.set(Calendar.MINUTE, minute); updatelabel(); } }; private void updatelabel() { // TODO Auto-generated method stub lblDateAndTime.setText(fmtDateAndTime.format(myCalendar.getTime())); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lblDateAndTime = (TextView) findViewById(R.id.lblDateAndTime); Button Btndate = (Button) findViewById(R.id.buttonDate); Btndate.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub new DatePickerDialog(DateandTimeActivity.this, d, myCalendar.get(Calendar.YEAR), myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH)).show(); } }); Button Btntime = (Button) findViewById(R.id.buttonTime); Btntime.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub new TimePickerDialog(DateandTimeActivity.this, t, myCalendar.get(Calendar.HOUR_OF_DAY), myCalendar.get(Calendar.MINUTE), true).show(); } }); updatelabel(); } } dp.init(1992, 9, 19, null); TimePicker tp = (TimePicker) this.findViewById(R.id.timePicker); Dasar Pemrograman Android Page 139 tp.setIs24HourView(true); tp.setCurrentHour(new Integer(10)); tp.setCurrentMinute(new Integer(10)); } Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.18 Tampilan DatePicker dan TimePicker. b. AnalogClock dan DigitalClock Selain menentukan tanggal dan waktu, Android juga menyediakan widget untuk menampilkan Tanggal dan Waktu. Berikut adalah potongan kode dalam bentuk XML. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"> <AnalogClockandroid:layout_width="wrap_content" android:layout_height="wrap_content"/> <DigitalClockandroid:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> Dasar Pemrograman Android Page 140 Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.19 Tampilan AnalogClock dan DigitalClock. Dapat dilihat di atas bahwa AnalogClock pada Android memiliki dua jarum jam yang berfungsi untuk menunjukkan jam dan menit. Selain itu, terdapat DigitalClock untuk menampilkan waktu dalam bentuk digital. 3.7.12 MapView dan WebView MapView berfungsi menampilkan peta pada aplikasi, namun MapView tidak akan dibahas di dalam bab ini, melainkan akan dibahas pada bab IV. WebView digunakan untuk menampilkan halaman web. Tetapi sama seperti MapView, hal ini juga akan dibahas lebih lanjut pada bab IV. 3.7.13 Gallery Gallery adalah sebuah layoutwidget yang digunakan untuk menampilkan item secara horizontal dan memposisikan item yang sedang dipilih pada bagian tengah screen. Berikut adalah potongan kode dalam bentuk XML. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Gallery xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/galleryCtrl" android:layout_width="fill_parent" android:layout_height="wrap_content" /> Dasar Pemrograman Android Page 141 <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="fitXY" /> </LinearLayout> Berikut ini adalah potongan kode pemanggilan Gallery menggunakan kode Java. Kode ini diletakkan dalam method onCreate(): Gallery g = (Gallery) findViewById(R.id.galleryCtrl); g.setAdapter(new ImageAdapter(this)); g.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(getBaseContext(), "" + arg2,Toast.LENGTH_SHORT).show(); ImageView imageView = (ImageView)findViewById(R.id.imageView1); imageView.setImageResource(mImageIds[arg2]); } }); Dimulai dengan dengan mengatur layout dari main.xml sebagai konten dari view dan menangkap Gallery dari layout dengan findViewById(int). Kemudian BaseAdapter dipanggil, dan ImageAdapter akan diinstansikan dan ditambahkan pada Gallery dengan setAdapter(). Kemudian sebuah AdapterView.OnItemClickListener akan diinstansiasikan onItemClick(AdapterView, View, int, long). Berikut adalah sebuah custom styleable resource yang dapat diaplikasikan pada sebuah layout. Dalam hal ini, akan diaplikasikan kepada setiap item individual di dalam Gallery. <?xmlversion="1.0"encoding="utf-8"?> <resources> <declare-styleable name="HelloGallery"> Dasar Pemrograman Android Page 142 <attr name="android:galleryItemBackground"/> </declare-styleable> </resources> Elemen <attr> mendefinisikan sebuah atribut spesifik untukstyleable, dan dalam hal ini, mengacu kepada platformattribute, yaitu galleryItemBackground yang mendefinisikan sebuah border styling untuk gallery item. Dalam langkah berikutnya, akan terlihat bagaimana atribut ini direferensikan lalu diaplikasikan kepada setiap item pada Gallery. Dasar Pemrograman Android Page 143 public class ImageAdapter extends BaseAdapter { int mGalleryItemBackground; private Context mContext; private Integer[] mImageIds = { R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7 }; public ImageAdapter(Context c) { mContext = c; TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery); mGalleryItemBackground = a.getResourceId( R.styleable.HelloGallery_android_galleryItemBackground, 0); a.recycle(); } publicint getCount() { return mImageIds.length; } public Object getItem(int position) { return position; } Public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ImageView i = new ImageView(mContext); i.setImageResource(mImageIds[position]); i.setLayoutParams(new Gallery.LayoutParams(150, 100)); i.setScaleType(ImageView.ScaleType.FIT_XY); i.setBackgroundResource(mGalleryItemBackground); return i;}} Dasar Pemrograman Android Page 144 Pertama-tama, ada beberapa variabel, termasuk sebuah array yang berisikan ID yang mereferensi kepada gambar-gambar yang disimpan di dalam (res/drawable/). Kemudian ada constructor, di mana Context untuk ImageAdapter didefinisikan di sini, beserta dengan styleableresource yang didefinisikan pada langkah terakhir dan disimpan di sebuah localfield. Pada akhir dari constructor, recycle() dipanggil pada TypedArray , agar bisa digunakan kembali oleh system. Method getCount(), getItem(int), dan getItemId(int) adalah method yang harus diimplementasikan untuk beberapa query sederhana yang ada di Adapter. Method tersebut bertugas memasang image pada android.widget.ImageView yang kemudian dipasangkan di dalam Gallery. Di dalam method ini, Context bertugas untuk membuat sebuah ImageView baru. ImageView dibuat dengan memasang sebuah image dari localarray dari sebuah drawable resource, mengatur Gallery.LayoutParams, tinggi dan lebar untuk image dengan menggunakan mengatur skala agar sesuai dengan dimensi ImageView, kemudian mengatur background dengan menggunakan atribut styleable yang diperoleh dari constructor. Gambar 3.20 Tampilan Gallery. Dasar Pemrograman Android Page 145 3.7.14 Spinner Spinner merupakan sebuah widget yang mirip dengan drop-downlist. Pada bagian ini, akan dijelaskan bagaimana cara membuat sebuah spinner sederhana yang akan menampilkan nama-nama kota. Pada saat terpilih, maka sebuah pesan akan keluar dengan menampilkan item yang dipilih. <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="Nama-nama kota di Indonesia" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> Perhatikan atribut dari TextView yaitu android:text yang akan berperan sebagai title dari widget. Pada saat dipasang pada Spinner, maka title akan muncul di selection dialog yang muncul diatas widget yang di pilih. Selanjutnya adalah menambahkan string-array kedalam tag <resources></resources> pada file strings.xml yang terdapat pada folder /res/values. string-array digunakan untuk menyimpan daftar item yang akan ditampilkan di dalam spinner. <string-array name="planet_array" > <item>Bumi</item> <item>Jupiter</item> <item>Mars</item> <item>Merkurius</item> Dasar Pemrograman Android Page 146 <item>Neptunus</item> <item>Saturnus</item> <item>Uranus</item> <item>Pluto</item> <item>Venus</item> </string-array> Berikut adalah file SpinnerActivity.java untuk menampilkan spinner pada emulator. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); planet = getResources().getStringArray(R.array.planet_array); Spinner spinner = (Spinner) findViewById(R.id.spinner); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, planet); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub int index = arg0.getSelectedItemPosition(); Toast.makeText(getBaseContext(), "You have selected item : " + planet[index], Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); } Dasar Pemrograman Android Page 147 Setelah layout dari main.xml diatur menjadi content view, Spinner widget akan diterima dari method findViewById(int). Kemudian method createFromResource() akan membuat sebuah ArrayAdapter yang baru. ArrayAdapter tersebut akan mengikat setiap item di dalam stringarray pada awal kemunculan Spinner (item akan keluar setiap saat spinner dipilih). IDR.array.planets_array mengacu android.R.layout.simple_spinner_item pada string-array dan ID. mengacu pada layout standar saat kemunculan spinner. Lalu setDropDownViewResource(int) dipanggil untuk mendefinisikan penampilan setiap item pada saat widget dibuka (simple_spinner_dropdown_item adalah standard layout yang didefinisikan oleh platform). Akhirnya, ArrayAdapter diatur untuk mengasosiasikan semua item dengan Spinner dengan memanggil setAdapter(T). Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.21 Tampilan Spinner. Dasar Pemrograman Android Page 148 3.7.15 Layout Managers Seperti Swing, Android menawarkan class-class yang berperan sebagai container. container ini dinamakan sebagai layout atau layout manager, dalam implementasinya layout ini digunakan untuk mengatur ukuran dan posisi dari class turunannya. Berikut ini adalah layout manager beserta penjelasannya: Layout Manager Deskripsi LinearLayout Mengatur posisi layout pada layar secara linear (horisontal ataupun vertikal). RelativeLayout Mengatur posisi layout pada layar secara relative(relatif) TableLayout Mengatur layout agar berbentuk seperti tabel. FrameLayout Mengatur layout yang memungkinkan untuk mengubah tata letak komponen. TabLayout Mengatur layout agar dapat berbentuk tab. 3.7.15.1 Linear Layout Linear Layout adalah salah satujenis layoutyang paling sederhana yangdisediakan oleh Android. Linear Layout mengatur tata letak komponen secara linear horisontal atau vertikal. <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="red" android:gravity="center_horizontal" android:background="#aa0000" android:layout_width="fill_parent" Dasar Pemrograman Android Page 149 android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="green" android:gravity="center_horizontal" android:background="#00aa00" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="blue" android:gravity="center_horizontal" android:background="#0000aa" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="yellow" android:gravity="center_horizontal" android:background="#aaaa00" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="red" android:gravity="center_horizontal" android:background="#aa0000" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="green" Dasar Pemrograman Android Page 150 android:gravity="center_horizontal" android:background="#00aa00" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="blue" android:gravity="center_horizontal" android:background="#0000aa" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="yellow" android:gravity="center_horizontal" android:background="#aaaa00" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> </LinearLayout> Ini adalah Linear Layout Android sederhana. Tata letak ini menetapkan orientasi vertikal dan horizontal. Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.22 Tampilan Linear Layout. Dasar Pemrograman Android Page 151 a. Mengenal weight dan gravity Atribut orientation merupakan atribut terpenting dalam LinearLayout. Untuk mengatur ukuran dan posisi, digunakan weight dan gravity. Weight digunakan untuk mengatur besar dan gravity berfungsi sebagai alignment. Sebagai contoh, jika menginginkan tulisan rata kanan, maka gravity perlu diatur menjadi right. Contoh beberapa nilai untuk gravity: left, center,right, top, bottom, center_horizontal, center_vertical dan masih banyak lagi. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="0.0" android:gravity="left" android:text="one"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1.0" android:gravity="center" android:text="two"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="0.0" android:gravity="right" android:text="three"/> </LinearLayout> Dasar Pemrograman Android Page 152 Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.23 Tampilan Linear Layout yang memiliki pengaturan weight dan gravity. b. Android:gravity dan Android:layout_gravity Android mendefinisikan dua jenis atribut gravity yaitu android:gravity dan android:layout_gravity. view sedangkan Perbedaannya adalah android:gravity digunakan untuk mengatur android:layout_gravity digunakan untuk mengatur container (android.view.ViewGroup). Sebagai contoh, android:gravity dapat diatur agar menjadi rata tengah dalam penggunaan teks di EditText dan dapat mengatur EditText menjadi rata kanan dengan android:layout_gravity=”right”. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:layout_width="wrap_content" android:gravity="center" android:layout_height="wrap_content" android:text="one" android:layout_gravity="right"/> </LinearLayout> Dasar Pemrograman Android Page 153 Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.24 Tampilan layout_gravity. c. Table Layout TableLayout adalah sebuah ViewGroup yang memperlihatkan elemen view dalam bentuk baris dan kolom. Untuk menggunakan Table Layout, tambahkan Table Layout pada layout XML kemudian lanjutkan dengan menggunakan Table Row. Table Row digunakan untuk mengatur elemen pada tabel. <TableLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"android:layout_height="fill_parent"> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nama Depan:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Metra"/> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nama Belakang:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="C. Utama"/> </TableRow> </TableLayout> Dasar Pemrograman Android Page 154 Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.25 Tampilan Tabel Layout. Konten pada Table Layout didefinisikan oleh baris dan tidak berhubungan dengan kolom. Hal ini mengakibatkan Android menjadi penentu pada pembuatan jumlah kolom. Sebagai contoh, apabila hendak membuat dua baris dimana baris pertama memiliki dua cell dan baris kedua memiliki tiga cell, maka Android akan membuat dua baris dan tiga kolom dimana pada baris pertama memiliki cell yang kosong. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nama Depan:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cahya"/> </TableRow> Dasar Pemrograman Android Page 155 <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nama Belakang:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Metra"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content"android:text="Utama"/> </TableRow> </TableLayout> Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.26 Tampilan Tabel Layout tiga kolom. Meskipun pola Table android.widget.View Layout dengan elemen Table Row sering digunakan, dapat ditempatkan sebagai turunan di dalam tabel. Sebagai contoh, baris pertama adalah TextView. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" Dasar Pemrograman Android Page 156 android:stretchColumns="0,1,2"> <EditText android:text="Nama Lengkap:"/> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Metra"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cahya"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"android:text="Utama"/> </TableRow> </TableLayout> Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.27 Tampilan Tabel Layout tampa menggunakan Table Row. EditText mengambil seluruh lebar layar, meskipun belum ditentukan di XML layout. Hal itu dikarenakan turunan dari Table android:layout_width=”wrap_content”. Layout EditText tidak tersebut bisa dipaksa menentukan untuk menerima fill_parent. Karena isi tabel tidak selalu diketahui pada saat desain, Table Layout menawarkan beberapa atribut yang Dasar Pemrograman Android dapat membantu kita dalam mengatur tata letak. Page 157 android:stretchColumns = “0,1,2” memberikan petunjuk untuk TableLayout bahwa kolom 0,1,2 dapat diatur berdasarkan isi tabel. android:shrinkColumns dapat digunakan untuk mengatur isi kolom atau kolom jika kolom lain memerlukan lebih banyak ruang. Selain itu juga dapat mengatur android:collapseColumns untuk membuat kolom menjadi tidak terlihat. Catatan bahwa kolom yang diidentifikasi pengindeks-annya berbasis nol. TableLayout juga menawarkan android:layout_span. Kita dapat menggunakan atribut ini untuk menampilkan cell span pada beberapa kolom. Sama halnya dengan colspan pada HTML. Kadangkala juga perlu memberi jarak pada setiap cell. Android mendukung ini melalui android:padding dan lain-lain. android:padding memungkinkan untuk mengatur ruang antara view dan content. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal"android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="one" android:padding="40px"/> </LinearLayout> Kode di atas menampilkan 40 pixel ruang putih antara garis luar EditText dengan teks yang berada di dalamnya. Gambar dibawah ini menunjukkan perbandingan antara menggunakan padding dan yang tidak menggunakan padding. Gambar 3.28 Tampilan TabelLayout android:padding. Dasar Pemrograman Android Page 158 android:padding mengatur padding atau ketebalan untuk semua sisi: kiri, kanan, atas dan bawah. Selain itu, padding untuk bagian depan juga dapat diatur dengan menggunakan android:leftPadding, android:bottomPadding. android:rightPadding, android:topPadding dan Android juga mendefinisikan android:layout_margin yang memiliki fungsi hampir sama dengan android:padding. Bahkan android:padding atau android:layout_margin yang dapat diilustrasikan seperti android:gravity atau android:layout_gravity. Berikut jenis-jenis satuan ukuran yang didukung oleh Android: a. Pixels :pixel disingkat sebagai px. b. Inches : inchi, disingkat sebagai in c. Milimeters : milimeter, disingkat mm d. Points disingkat pt. Satu (1) Pt sama dengan 1/72 inci. e. Density-independent pixels: disingkat dpi atau dp. Density-independent pixel sama dengan satu pixel pada layar 160-dpi. f. Scale-independent pixels: disingkat sp. Umumnya scale-independent pixels berhubungan dengan jenis font. Jenis dimensi font yang akan ditampilkan mengacu pada pengaturan font, kemudian Android akan menentukan ukuran sebenarnya. d. Relative Layout Relative Layout mengatur tata letak komponen dalam hubungan atar satu dengan yang lainnya. Hal ini memberikan fleksibilitas yang lebih untuk penentuan tata letak dengan memanfaatkan Linear Layout. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/penggunaNameLbl" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Penggunaname: " android:layout_alignParentTop="true"/> <EditText android:id="@+id/penggunaNameText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/penggunaNameLbl"/> <TextView android:id="@+id/pwdLbl" Dasar Pemrograman Android Page 159 android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/penggunaNameText" android:text="Password: "/> <EditText android:id="@+id/pwdText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/pwdLbl"/> <TextView android:id="@+id/pwdHintLbl" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/pwdText" android:text="Password Criteria... "/> <TextView android:id="@+id/disclaimerLbl" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="Kevin R. Octavian "/> </RelativeLayout> Hasil potongan kode di atas adalah sebagai berikut: Gambar 3.29 Tampilan Relative Layout. Dasar Pemrograman Android Page 160 Kode di atas menghasilkan program yang menampilkan form seperti yang terlihat pada gambar 3.9.7. Label username terletak di atas, karena di dalam kode ditetapkan nilai dari android:layout_alignParentTop adalah “true”. Label password muncul di bawah label username karena terdapat kode android:layout_alignParentBottom=”true”. Selain atributatribut layout tersebut, layout juga dapat ditentukan layout_toRightOf, layout_toLeftOf, layoutcenterInParent e. dengan layout_above, dan beberapa kode lainnya. Frame Layout Layout Manager yang dibahas sampai saat ini mengimplementasikan berbagai layout. Masing-masing layout memiliki metode sendiri untuk memposisikan turunannya di layar. Dengan Layout Manager, dapat memiliki banyak kontrol pada layar. Masing-masing mengambil sebagian dari layar. Android juga menawarkan Layout Manager yang digunakan untuk menampilkan item tunggal. Layout Manager ini disebut Frame Layout. Penggunaan layout ini biasanya tidak hanya untuk menampilkan secara dinamis satu view, namunjuga dapat diisi dengan banyak item. <FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/frmLayout" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageViewandroid:id="@+id/seamolec" android:src="@drawable/logo_seamolec" android:scaleType="fitCenter" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <ImageViewandroid:id="@+id/jarc" android:src="@drawable/logo_jarc" android:scaleType="fitCenter" android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone"/> </FrameLayout> Berikut ini adalah potongan kode FrameLayout menggunakan kode Java: Dasar Pemrograman Android Page 161 ImageView seamolec = (ImageView)this.findViewById(R.id.seamolec); ImageView jarc = (ImageView)this.findViewById(R.id.jarc); seamolec.setOnClickListener(new OnClickListener(){ publicvoid onClick(View view) { ImageView jarc = (ImageView)Main.this. findViewById(R.id.jarc); jarc.setVisibility(View.VISIBLE); view.setVisibility(View.GONE); }}); jarc.setOnClickListener(new OnClickListener(){ publicvoid onClick(View view) { ImageView seamolec = (ImageView)Main. this.findViewById(R.id.seamolec); seamolec.setVisibility(View.VISIBLE); view.setVisibility(View.GONE); }}); Kode di atas digunakan untuk memuat dua ImageView di FrameLayout dengan menggunakan salah satu objek ImageView. Seperti yang telah dijelaskan bahwa pada umumnya untuk menangani hal ini dapat menggunakan FrameLayout, yaitu mengatur secara dinamis isi dari view kontrol. Meskipun ini adalah hal yang biasa, kontrol akan menerima banyak turunan, seperti yang ditunjukkan menambahkan dua kontrol ke layout tetapi memiliki salah satu control yang terlihat pada satu waktu. Jika menambahkan banyak komponen pada layout, FrameLayout hanya akan menumpukkan komponen tersebut dengan yang terakhir di posisi teratas. Gambar 3.30 Tampilan FrameLayout. Dasar Pemrograman Android Page 162 Aspek lain yang menarik dari FrameLayout adalah jika menambahkan lebih dari satu komponen ke layout, ukuran layout dihitung sebagai ukuran dari item terbesar di container. f. Tab Layout Dalam membuat tabbedUI, digunakan TabHost dan TabWidget. Tabhost harus merupakan rootnode untuk layout-nya, yang isinya baik TabWidget untuk menampilkan tab atau FrameLayout untuk menampilkan isi dari tab. Untuk mengimplementasikan isi dari tab bisa dilakukan dengan dua cara, yaitu dengan menggunakan tab untuk mengganti View dalam Activity yang sama, atau menggunakan tab untuk mengganti semua activity yang terpisah. publicclass LaguBarat extends Activity { publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textview = new TextView(this); textview.setText("Ini adalah dafatar Lagu Barat"); setContentView(textview); } } publicclass LaguBaru extends Activity { publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textview = new TextView(this); textview.setText("Ini adalah dafatar Lagu Baru"); setContentView(textview); } } publicclass LaguLama extends Activity { publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textview = new TextView(this); textview.setText("Ini adalah dafatar Lagu Lama"); setContentView(textview); }} Dasar Pemrograman Android Page 163 Activity diatas merupakan isi dari setiap tab. Jangan lupa untuk menambahkan setiap Activity ke dalam AndroidManifest.xml <activity android:name=".LaguLama"></activity> <activity android:name=".LaguBaru"></activity> <activity android:name=".LaguBarat"></activity> <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!—Ketika dipilih, warna menjadi abu-abu --> <item android:drawable="@drawable/ic_tab_artists_grey" android:state_selected="true"/> <!—Ketika tidak dipilih,warna menjadi putih--> <item android:drawable="@drawable/ic_tab_artists_white"/> </selector> Ini adalah sebuah state-list drawable, hal ini akan digunakan sebagai tabimage. Saat tabstate berganti, maka tabicon akan berganti secara otomatis (antara aktif atau tidak aktif). <TabHostxmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dp"> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dp" /> </LinearLayout> Dasar Pemrograman Android Page 164 </TabHost> Kode-kode di atas akan menghasilkan layout yang menampilkan semua tab dan mengatur navigasi pada setiap navigasi yang dibuat. TabHost membutuhkan baik TabWidget dan FrameLayout untuk bekerja di dalam TabHost. Untuk memposisikan TabWidget dan FrameLayout secara vertikal, maka diperlukan sebuah LinearLayout. FrameLayoutmemang merupakan tempat di mana semua konten dari setiap tab dijalankan, namunmasih tetap dalam keadaan kosong karena TabHost akan langsung meng-embed setiap Activity di dalamnya. Perhatikan bahwa elemen dari TabWidget dan FrameLayout memiliki ID dari tab dan tab content secara perspektif. Resources res = getResources(); TabHost tabHost = getTabHost(); TabHost.TabSpec spec; Intent intent; intent = new Intent().setClass(this, LaguLama.class); spec = tabHost.newTabSpec("artists").setIndicator("Lagulama", res.getDrawable(R.drawable.tab_btn)) .setContent(intent); tabHost.addTab(spec); intent = new Intent().setClass(this, LaguBaru.class); spec = tabHost.newTabSpec("albums").setIndicator("Lagubaru", res.getDrawable(R.drawable.tab_btn)) .setContent(intent); tabHost.addTab(spec); intent = new Intent().setClass(this, LaguBarat.class); spec = tabHost.newTabSpec("songs").setIndicator("Lagubarat", res.getDrawable(R.drawable.tab_btn)) .setContent(intent); tabHost.addTab(spec); tabHost.setCurrentTab(2); Kode di atas mengatur setiap tab beserta text dan icon serta menempatkan Activity di masing-masing tab. Sebuah referensi ke TabHost pertama akan ditampilkan menggunakan getTabHost(). Kemudian, untuk setiap tab, Tabhost.Spec akan dibuat untuk mendefinisikan Dasar Pemrograman Android Page 165 tab properties-nya. newTabSpec(String) method membuat sebuah TabHost.TabSpec yang baru yang di identifikasi dengan mengganti string tag. Untuk setiap TabHost.TabSpec, setIndicator(CharSequence, Drawable) akan dipanggil untuk mengatur text dan icon untuk setiap tab, dan setContent(Intent) akan dipanggil untuk menspesifikasikan Intent untuk membuka Activity. Setiap TabHost.TabSpec akan ditambahkan kepada TabHost dengan memanggil addTab(TabHost.TabSpec). Pada akhirnya, setCurrentTab(int) akan membuka tab yang akan ditampilkan secara default, dispesifikasikan oleh posisi index dari tab. Perhatikan bahwa tidak hanya sekali object TabWidget direferensikan. Ini karena TabWidget selalu merupakan turunan dari TabHost, di mana hampir setiap kali digunakan untuk berinteraksi dengan tab. Jadi pada saat sebuah tab ditambahkan kepada TabHost, maka akan secara otomatis ditambahkan kepada “child” TabWidget. Gambar 3.31 Tampilan TabLayout. g. Penyesuaian Layout Sekarang sudah diketahui bahwa Android menawarkan sejumlah LayoutManager yang dapat membantu dalam membangun penggunaan interface. Jika sudah terbiasa dengan layout manager, maka dapat dengan mudah menggabungkan beberapa layout manager agar mendapatkan tampilan seperti yang diinginkan. Pengguna dan produsen perangkat mobile yang semakin canggih, membuat para developer atau pengembang menjadi lebih menantang. Salah satu tantangannya adalah membangun UI untuk aplikasi yang menampilkan berbagai konfigurasi di layar. Dasar Pemrograman Android Page 166 Sebagai contoh, apa yang akan UI lakukan apabila aplikasi ditampilkan dalam modus potrait atau landscape?. Android menyediakan beberapa dukungan terhadap kasus ini. Cara kerjanya Android akan menemukan dan menampilkan layout dari folder tertentu berdasarkan konfigurasi perangkat. Sebuah perangkat dapat berada dalam salah satu dari ketiga konfigurasi ini: potrait, landscape dan square. Untuk memberikan layout yang berbeda, maka harus membuat folder khusus untuk masing-masing konfigurasi dimana Android akan memuat layout yang sesuai. Seperti yang telah diketahui, folder default layout terletak di “res atau layout”. Untuk mendukung tampilan portrait buatlah folder bernama res/layout-port. Untuk landscape , buatlah folder bernama res/layoutland, dan untuk square, buat sebuah folder res atau layoutsquare. Perlu perhatikan juga bahwa Android SDK tidak menawarkan API untuk menentukan konfigurasi dalam memuat sistem dengan hanya memilih folder berdasarkan konfigurasi perangkat. Namun orientasi perangkat dapat diatur dalam kode, misalnya: import android.content.pm.ActivityInfo …… setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); Hal ini akan memaksa aplikasi muncul dalam modus landscape. 3.8 Adapter Adapter pada umumnya bertugas mengikat data dengan mudah dan lebih fleksibel. Adapter di Android yang android.widget.AdapterView. GridView, Spinner dan android.widget.ViewGroup digunakan untuk widget merupakan turunan dari Class yang meng-extend AdapterView termasuk ListView, Gallery. AdapterView sendiri merupakan turunan dari yang berarti bahwa ListView, GridView dan yang lainnya merupakan container control. Dasar Pemrograman Android Page 167 View ViewGroup AdapterView ListView GridView Spinner Gallery Gambar 3.32 Tampilan Hirarki View Tujuan dari Adapter adalah memberikan childview untuk kontainer. Dibutuhkan data dan meta data tentang pandangan untuk membangun setiap tampilan dari turunannya. Berikut adalah cara kerja dari SimpleCursorAdapter. Constructor dari SimpleCursorAdapter adalah seperti berikut: SimpleCursorAdapter(Context context),int layout,Cursor c,String[] from,int[] to). Adaptor ini mengkonversi baris dalam kursor ke tampilan turunannya. Definisi dari pandangan turunannya didefinisikan dalam sumber daya XML (parameterlayout). Perhatikan bahwa baris dalam kursor memungkinkan untuk memiliki banyak kolom, Untuk menetapkan kolom dan baris yang ingin dipilih pada SimpleCursorAdapter, dapat dilakukan dengan menetapkan sebuah array nama kolom(menggunakan parameter). Karena setiap kolom yang terpilih dipetakan ke TextView, maka harus terlebih dahulu menentukan ID terhadap parameter. Ada pemetaan one-to-one antara kolom yang dipilih dan TextView yang menampilkan data dalam kolom, sehingga data ke parameter ukurannya sama. Dasar Pemrograman Android Page 168 3.8.1 ArrayAdapter ArrayAdapter adalah adapter yang paling sederhana di Android. ArrayAdapter mengasumsikan bahwa TextView merupakan anggota item (dalam turunannya). Berikut ini adalah contoh pembuatan ArrayAdapter : ArrayAdapter<String> adapter = new ArrayAdapter<String>( this,android.R.layout.contoh_list_item, new String[]{"Kevin","Renata",”Octavian”}); Contructor dalam kode ArrayAdapter menciptakan data yang diwakili oleh String, lalu disimpan ke dalam TextView. Sebagai catatan: android.R.layout.contoh_list_item merujuk ke TextView yang didefinisikan oleh Android SDK.ArrayAdapter, menyediakan sebuah method yang berguna apabila data untuk list berasal dari file. <string-arrayname="planet"> <item>Merkurius</item> <item>Venus</item> <item>Bumi</item> <item>Mars</item> <item>Jupiter</item> <item>Saturnus</item> <item>Uranus</item> <item>Neptunus</item> <item>Pluto</item> </string-array> Berikut ini adalah potongan code dalam pembuatan ArrayAdapter: Spinner s2 = (Spinner) findViewById(R.id.spinner2); adapter = ArrayAdapter.createFromResource(this, R.array.planets,android.R.layout.spinner_item); adapter.setDropDownViewResource(android.R.layout.spinner); s2.setAdapter(adapter); Array Adapter memiliki method utilitas yang disebut createFromResource(), yang dapat membuat Array Adapter dari data dalam filestring. Menggunakan method ini Dasar Pemrograman Android Page 169 memungkinkan tidak hanya eksternalisasi isi daftar untuk fileXML, tetapi juga menggunakan locale version. 3.8.2 Custom Adapters Adapter di Android begitu mudah digunakan, namun juga memiliki beberapa keterbatasan. Untuk itu, Android menyediakan abstract class yang disebut Base Adapter yang dapat diturunkan jika memerlukan custom adapter. Dengan demikian, jika ingin menurunkan Adapter, dapat langsung menggunakan adapter berikut ini: a. ArrayAdapters<T>: Ini adalah adapter yang memiliki tingkatan di atas arrayobject. Biasa digunakan dengan ListView. b. CursorAdapter : Adapter ini digunakan dalam ListView. Adapter ini menyediakan data melalui kursor. c. SimpleAdapter : Seperti namanya, adapter ini adalah adapter yang sederhana. Adapter ini umumnya digunakan untuk mengisi daftar dengan data statis. d. ResourceCursorAdapter : Adapter ini merupakan turunan dari CursorAdapter dan biasa digunakan membuat view atau tampilan dari resource. e. SimpleCursorAdapter : Adapter ini merupakan turunan dari ResourceCursorAdapter dan berfungsi membuat TextView atau ImageView dari kolom dalam kursor. 3.9 Menu Android menyajikan beberapa pola menu seperti menu dari XML dan menu alternatif. Bahasan ini akan dimulai dengan menggambarkan class dasar yang terlibat dalam kerangka menu Android. Dalam prosesnya, akan diajarkan cara membuat menu dan item, serta bagaimana untuk merespon item menu. Class utama dalam yang digunakan adalah android.view.Menu. Setiap Activity di Android dikaitkan dengan object menu jenis ini, yang dapat berisi sejumlah menu dan submenu. Item menu ini diwakili oleh android.view.MenuItem dan submenu diwakili oleh android.view.SubMenu. Gambar dibawah ini bukan merupakan diagram class, tetapi struktur diagram yang dirancang untuk membantu visualisasi hubungan antar class yang terkait dengan berbagai menu dan fungsi. Dasar Pemrograman Android Page 170 Activity ModuleMenu Berisi single menu Menu berisi berisi MenuItem berisi SubMenu onCreateOptionsMenu() onOptionsItemSelected() Gambar 3.32 Hubungan Activity dengan Menu. Menu group item dapat dibuat dengan menetapkan masing – masing IDgroup. Beberapa menu yang membawa IDgroup yang sama dianggap sebagai bagian dari kelompok yang sama. Selain memuat IDgroup, sebuah menu item juga memuat judul, sebuah IDmenu-item dan IDsortorde. IDsort-order digunakan untuk menentukan urutan item didalam menu. Misalnya, jika satu item memuat sort-order berjumlah empat dan item yang lain memuat sejumlah sort-order berjumlah 6, maka item yang pertama akan muncul diatas item kedua di dalam menu. Tidak banyak rentang order-number yang dicadangkan bagi beberapa jenis menu. Item yang dianggap kurang penting daripada yang lain, mulai dari 0x30000 dan didefinisikan oleh konstanMenu.CATEGORY_SECONDARY. Bentuk lain dari kategori menu seperti sistem menu, alternatif menu dan kontainer menu yang memiliki perbedaan rentang order number. Sistem menu dimulai dari 0x20000 dan didefinisikan oleh konstanta Menu.CATEGORY_SYSTEM. Menu alternatif dimulai dari 0x40000 dan didefinisikan oleh konstanta Menu.CATEGORY_ALTERNATIVE. Container menu dimulai dari 0x10000 dan didefinisikan oleh konstan Menu.CATEGORY_CONTAINER. Dasar Pemrograman Android Page 171 Dalam Android SDK, tidak diperlukan untuk membuat objek menu dari awal. Karena sebuah Activity dikaitkan dengan single menu. Android menciptakan single menu ini untuk Activity dan meneruskannya ke method callback onCreateOptionsMenu dari classActivity. @Override publicboolean onCreateOptionsMenu(Menu menu){ // mengatur menu items . . . . returntrue; } Setelah menu item diisi, tambahkan return true dibagian akhir kode untuk menampilkan menu. Sebaliknya, jika menuliskan return false maka menu tidak akan terlihat. Kode dibawah ini merupakan contoh bagaimana menambahkan tiga menuitem menggunakan singlegroupID bersama dengan tambahan IDmenuitem dan IDsort-order. @Override publicboolean onCreateOptionsMenu(Menu menu){ //memanggil class dasaruntukmenyertakan menu sistem super.onCreateOptionsMenu(menu); menu.add(0 // Group ,1 // item id ,0 //order ,"judul"); // judul menu.add(0,2,1,"item2"); menu.add(0,3,2,"bersihkan"); //inisangatpentinguntukmenampilkan menu returntrue; } Dalam menjaga sistem menu item yang terpisah dari menu item jenis lain, Android menambahkan mulai 0x20000 (Seperti yang telah disebutkan sebelumnya, konstan Menu.CATEGORY_SYSTEM mendefinisikan ID awal untuk sistem menu item ini). Parameter pertama yang diperlukan untuk menambahkan menuitem adalah IDgroup (integer). Parameter kedua adalah IDmenu-item yang dikirim kembali ke methodcallback ketika menuitem dipilih. Parameter ketiga merupakan IDsort-order. Parameter terakhir adalah nama atau judul dari Dasar Pemrograman Android Page 172 itemmenu tersebut yang dapat menggunakan string melalui file konstan R.java. Kelompok ID ini, IDmenu-item dan IDsort-order semua opsional, dapat digunakan Menu.NONE jika tidak ingin menentukan apapun. Berikutnya adalah bekerja dengan menugroups. @Override publicboolean onCreateOptionsMenu(Menu menu){ //Group 1 int group1 = 1; menu.add(group1,1,1,"g1.item1"); menu.add(group1,2,2,"g1.item2"); //Group 2 int group2 = 2; menu.add(group2,3,3,"g2.item1"); menu.add(group2,4,4,"g2.item2"); returntrue; // ini sangat penting untuk menampilkan menu } Perhatikan bagaimana IDmenu-Item dan IDsort-order berdiri sendiri terhadap group. Jadi apa gunanya group?. Android menyediakan suatu set method yang didasarkan pada IDgroup. Group menu item dapat dimanipulasi dengan menggunakan method ini: removeGroup(id); setGroupCheckable(id, checkable, exclusive); setGroupEnabled(id,boolean enabled); setGroupVisible(id,visible); Method removeGroup menghapus semua menuitem dari group dengan IDgroup. Untuk mengaktifkan atau menonatifkan menu dalam suatu group tertentu, gunakan method setGroupEnabled. dilakukan Demikian juga untuk mengontrol visibilitas sekelompok menu item dapat dengan setGroupCheckable, menggunakan setGroupVisible. Kemudian ada juga method yang fungsinya adalah untuk menunjukkan tanda centang pada item saat item tersebut dipilih. Bila diterapkan ke group, akan memungkinkan fungsi ini untuk diterapkan pada semua item menu dalam kelompok tersebut. Jika method di-set, maka hanya satu menu item dalam group yang diperbolehkan untuk masuk. Item menu lain akan tetap dicentang. Sekarang sudah diketahui cara untuk mengisi Activity menu utama dengan satu setmenu dan group mereka sesuai dengan sifatnya. Selanjutnya, akan dilakukan bagaimana menanggapi menu item ini. Dasar Pemrograman Android Page 173 Ada beberapa cara untuk menanggapi klik pada menu-item di Android antara lain menggunakan method OnOptionsItemSelected dari class Activity, menggunakan listener yang berdiri sendiri, atau dapat menggunakan intent. Ketika sebuah menu item diklik, Android memanggil method onOptionsItemSelected pada class Activity. @Override publicboolean onOptionsItemSelected(MenuItem item){ switch(item.getItemId()) { } //untuk menangani item returntrue; //untuk sisanya returnsuper.onOptionsItemSelected(item); } Pola kunci disini adalah untuk menguji IDmenuitem melalui method getItemId() pada class Menu Item dan melakukan apa yang diperlukan. Jika onOptionsItemSelected() menangani item menu, itu mengembalikan nilai true, Menu event tidak akan lebih diperbanyak. Untuk menu-item, onOptionsItemSelected() tidak menangani, onOptionsItemselected() harus memanggil method induk melalui super.onOptionsItemselected(). Implementasi method onOptionsItemSelected() return false sehingga “normal” pemrosesan dapat berlangsung. Biasanya untuk menanggapi menu yaitu dengan meng-over ride onOptionsItemSelected, ini adalah teknik rekomendasi untuk performa yang lebih baik. Namun, menu item memungkinkan untuk mendaftar listener yang dapat digunakan sebagai callback. Pendekatan ini membutuhkan dua proses. OnMenuClickListener. Pada langkah pertama, kita menerapkan interface Lalu kita mengambil sebuah contoh dari implementasi ini dan selanjutnya ke item menu. Ketika item menu diklik, item menu akan memanggil method onMenuItemClick() dari interface onMenuClickListener. Method onMenuItemClick dipanggil saat menu item telah dipanggil. Kode ini mengeksekusi ketika item Dasar Pemrograman Android menu diklik, bahkan sebelum menjalankan method Page 174 onOptionsItemSelected. Jika onMenuItemClick mengembalikan nilai true, tidak ada callback lainnya akan dieksekusi termasuk method callback onOptionsItemselected. Ini berarti bahwa kode listener diutamakan atas method onOptionsItemselected. 3.10 Dialog Sebelum memulai pokok bahasan ini, coba perhatikan penjelasan berikut tentang dialog. Pada lingkungan sosial manusia, dialog berjalan seimbang, sebagai contoh, otak hanya berfungsi melakukan percakapan. Namun konsep dialog di atas berbeda dengan konsep dialog pada Android. Pada Android diperlukan pola pikir yang berbeda dari contoh dan penjelasan di atas. Dialog di Android berjalan tidak seimbang, yang dimaksud dengan tidak seimbang ini adalah seolah-olah bagian depan otak sedang melakukan percakapan, sedangkan bagian belakang otak berpikir untuk sesuatu yang lain. Tentu saja dialog yang tidak seimbang inisulit dilakukan pada manusia, namun "split-brain" dapat dilakukan pada program komputer. Dengan menggunakan pendekatan yang tidak seimbang tersebut, maka program dapat berjalan dengan lebih efektif lagi, sistem seperti ini juga dapat mengoptimalkan kinerja memori. Pada bagian berikut akan membahas aspek-aspek dialog Android secara mendalam. Akan dijelaskan juga apa saja komponen dialog dasar seperti alert dialog dan menunjukkan bagaimana cara untuk membuat dan menggunakannya. Kemudian juga akan ditunjukkan cara untuk bekerja dengan prompt dialog yang meminta pengguna untuk memasukkan input dan menampilkan kembali apa yang telah dimasukkan oleh pengguna dan akan dibahas bagaimana cara memuat layout ke dalam dialog. 3.10.1 Alert Dialog Alert Dialog adalah ekstensi dari class Dialog. Hal ini mampu membangun dialog interface dengan pengguna dan merupakan jenis dialog yang banyak digunakan. Untuk membuat AlertDialog, gunakan subclassAlertDialog.Builder. AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Apakah anda mau keluar?") .setCancelable(false) .setPositiveButton("Ya", new DialogInterface.OnClickListener() { publicvoid onClick(DialogInterface dialog, int id) { Dasar Pemrograman Android Page 175 Main.this.finish(); } }) .setNegativeButton("Tidak", new DialogInterface.OnClickListener() { publicvoid onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); Pada setiap AlertDialoghanya disediakan tiga tombol, yaitu positif, netral, dan negatif. Nama-nama ini secara teknis tidak bersangkutan dengan fungsi tombol yang sebenarnya, tetapi akan sangat membantu untuk melakukan sesuatu untuk aplikasi yang dibuat. Gambar 3.33 Tampilan Alert Dialog. Adapun langkah untuk menambahkan list ke dalam AlertDialog, gunakan method setItems(), tambahkan judul untuk dialog dengan menggunakan setTitle(), kemudian tambahkan daftar item yang dapat dipilih dengan setItems() untuk menerima data array yang berfungsi untuk menampilkan DialogInterface.OnClickListener yang bertugas untuk mendefinisikan tindakan yang dilakukan pada saat pengguna memilih item. final CharSequence[] warna = {"Merah", "Kuning", "Hijau" , "Biru"}; Dasar Pemrograman Android Page 176 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pilih warna kesukaan mu "); builder.setItems(warna, new DialogInterface.OnClickListener() { publicvoid onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(),warna[item], Toast.LENGTH_SHORT).show(); } }); AlertDialog alert = builder.create(); alert.show(); Berikut ini adalah hasil potongan kode di atas: Gambar 3.34 Tampilan Alert Dialog dalam bentul List. Dalam membuat daftar beberapa checkbox atau radio button di dalam dialog, dapat digunakan method setMultiChoiceItems() dan setSingleChoiceItems(). final CharSequence[] warna = {"Merah", "Kuning", "Hijau" , "Biru"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pilih warna favorit mu"); builder.setSingleChoiceItems(warna,-1,newDialogInterface.OnClickListener() { publicvoid onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(),warna[item], Toast.LENGTH_SHORT).show(); } Dasar Pemrograman Android Page 177 }); AlertDialog alert = builder.create(); alert.show(); Berikut ini adalah hasil potongan kode di atas: Gambar 3.35 Tampilan Alert Dialog dalam bentuk List. Parameter kedua pada method setSingleChoiceItems() adalah nilai integer untuk checked item, yang menunjukkan posisi item yang dipilih secara default. Gunakan "-1" untuk menunjukkan bahwa tidak ada item yang dipilih secara default. 3.10.2 Progress Dialog Progress Dialog adalah turunan dari class AlertDialog yang dapat menampilkan animasi progress dalam bentuk roda berputar. Dialog tipe ini juga dapat menampilkan tombol pada bar dialognya, misalnya untuk membatalkan download. Untuk menampilkan progress dialog dapat dilakukan dengan cara memanggil ProgressDialog.show(). ProgressDialog dialog = ProgressDialog.show(Main.this, "", "Sedang Memuat. harap tunggu...", true); dialog.show(); Berikut ini adalah hasil potongan kode di atas: Dasar Pemrograman Android Page 178 Gambar 3.36 Tampilan Progress Dialog. Dalam pembuatan progress dialog yang berbentuk bar, langkah yang dilakukan adalah menentukan parameter pertama sebagai context dari aplikasi, yang kedua adalah judul untuk dialog, yang ketiga adalah pesan yang ditampilkan dan parameter terakhir adalah apakah progress tersebut tetap ataukah tidak tetap. Bentuk default dari sebuah progress dialog adalah sebuah roda berputar. Jika ingin membuat sebuah progress bar yang menunjukkan bar loading, maka diperlukan sedikit perubahan pada kode, untuk lebih jelas perhatikan kode berikut ini: ProgressDialog progressDialog; progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Sedang memuat..."); progressDialog.setCancelable(false); progressDialog.show(); Berikut ini adalah hasil potongan kode di atas: Dasar Pemrograman Android Page 179 Gambar 3.37 Tampilan Progress Dialog berbentuk bar loading. Kebanyakan, kode yang digunakan untuk membuat sebuah progress dialog sebenarnya juga terlibat dalam proses tersebut. Mungkin dapat disimpulkan bahwa perlu membuat dua thread dalam aplikasi untuk menangani hal ini, dan kemudian melaporkan kembali ke thread utama dengan object Handler. Jika tidak terbiasa dengan menggunakan thread dengan Handler, maka dapat mengikuti contoh berikut ini. staticfinalintPROGRESS_DIALOG = 0; Button button; ProgressThread progressThread; ProgressDialog progressDialog; publicvoid onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); // Setup the button that starts the progress dialog button = (Button) findViewById(R.id.btn); button.setText("Mulai"); button.setOnClickListener(new OnClickListener(){ publicvoid onClick(View v){ showDialog(PROGRESS_DIALOG); } }); } Dasar Pemrograman Android Page 180 protected Dialog onCreateDialog(int id) { switch(id) { casePROGRESS_DIALOG: progressDialog = new ProgressDialog(Main.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Sedang memuat..."); progressThread = new ProgressThread(handler); progressThread.start(); returnprogressDialog; default: returnnull; } } // Handler yang menerima pesan dari thread dan update progress final Handler handler = new Handler() { publicvoid handleMessage(Message msg) { int total = msg.getData().getInt("total"); progressDialog.setProgress(total); if (total >= 100){ dismissDialog(PROGRESS_DIALOG); progressThread.setState(ProgressThread.STATE_DONE); } } }; privateclass ProgressThread extends Thread { Handler mHandler; finalstaticintSTATE_DONE = 0; finalstaticintSTATE_RUNNING = 1; intmState; inttotal; ProgressThread(Handler h) { mHandler = h; } publicvoid run() { mState = STATE_RUNNING; total = 0; while (mState == STATE_RUNNING) { try { Dasar Pemrograman Android Page 181 Thread.sleep(100); } catch (InterruptedException e) { Log.e("ERROR", "Thread Interrupted"); } Message msg = mHandler.obtainMessage(); Bundle b = new Bundle(); b.putInt("total", total); msg.setData(b); mHandler.sendMessage(msg); total++; } } // digunakan untuk menghentikan thread publicvoid setState(int state) { mState = state; } } Berikut ini adalah hasil potongan kode di atas: Gambar 3.38 Tampilan Progress Bar. 3.10.3 Custom Dialog Pada dasarnya tampilan custom dialog hampir sama seperti alert dialog, hanya saja yang membedakan adalah komposisi custom dialog dapat disusun sendiri. Misalnya saja, dalam custom dialog dapat dimuat gambar yang telah ditentukan. Dasar Pemrograman Android Page 182 Dalam pembuatan custom dialog, diperlukan setidaknya satu buah file xml yang berfungsi sebagai layout pada custom dialog. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_root" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="10dp" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="fill_parent" android:textColor="#FFF" /> </LinearLayout> Setelah layout dibuat, maka sisipkan kode berikut pada activity yang akan menampilkan dialog. dialog = new Dialog(this); dialog.setContentView(R.layout.custom_dialog); dialog.setTitle("Custom Dialog"); TextView text = (TextView) dialog.findViewById(R.id.text); text.setText("Halo, ini adalah custom dialog!"); ImageView image = (ImageView) dialog.findViewById(R.id.image); image.setImageResource(R.drawable.honeycomb); dialog.show(); Berikut adalah hasil potongan kode di atas : Dasar Pemrograman Android Page 183 Gambar 3.39 Tampilan Custom Dialog. 3.11 Animation Dalam bab ini, akan dijelaskan bagaimana cara membuat aplikasi agar lebih menarik dengan memanfaatkan kemampuan untuk menampilkan animasi yang disediakan oleh SDK Android. Animasi memerlukan banyak kreativitas dari seorang programmer. Animasi adalah suatu proses dimana sebuah objek pada layar berubah warna, posisi, ukuran, atau orientasi dari waktu ke waktu. Android mendukung tiga jenis animasi, yaitu: a. Animasi frame-by-frame, yang terjadi ketika serangkaian frame digambar satu demi satu pada interval reguler; b. Animasi tata letak, yaitu mengubah pandangan dari sudut pandang container seperti daftar dan tabel, c. Animasi visual, yaitu mengubah tampilan dari general purpose. Dua jenis terakhir masuk ke dalam kategori animasi Tweening, yang melibatkan gambar di antara gambar kunci. 3.11.1 Frame by frame animation Animasi frame-by-frame adalah proses sederhana yang menampilkan serangkaian gambar dalam urutan pada interval yang cepat sehingga menampilkan efek akhir suatu benda bergerak. Ini merupakan sistem dimana film proyektor bekerja. Untuk mencoba animasi frame-by-frame, maka ikutilah langkah – langkah berikut ini: Dasar Pemrograman Android Page 184 Langkah awal, masukkan gambar yang ingin diberikan efek animasi pada folder drawable, seperti gambar berikut: Gambar 3.39 memasukkan gambar pada folder drawable Berikut kode main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal"> <TextView android:id="@+id/textViewId1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Contoh animasi frame by frame"/> <Button android:id="@+id/startFAButtonId" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Start Animation"/> <ImageView android:id="@+id/animationImage" android:layout_width="50px" android:layout_height="58px" android:text="Mainkan animasi!"/> </LinearLayout> Dasar Pemrograman Android Page 185 Berikut kode animation.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal"> <TextView android:id="@+id/textViewId1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Contoh animasi frame by frame"/> <Button android:id="@+id/startFAButtonId" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Start Animation"/> <ImageView android:id="@+id/animationImage" android:layout_width="50px" android:layout_height="58px" android:text="Mainkan animasi!"/> </LinearLayout> Berikut kode Main.java <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/h1" android:duration="50"/> <item android:drawable="@drawable/h2" android:duration="50"/> <item android:drawable="@drawable/h3" android:duration="50"/> <item android:drawable="@drawable/h1" android:duration="50"/> <item android:drawable="@drawable/h2" android:duration="50"/> <item android:drawable="@drawable/h3" Dasar Pemrograman Android Page 186 android:duration="50"/> <item android:drawable="@drawable/h1" android:duration="50"/> <item android:drawable="@drawable/h2" android:duration="50"/> </animation-list> Berikut tampilan aplikasinya: Gambar 3.40 Tampilan pada Frame by frame animation Method animate() menempatkan ImageView dalam Activity yang sedang berjalan dan mengatur latar belakang ke dalam AnimationDrawable yang kemudian diidentifikasi oleh resource R.drawable.animation. Tombol memulai / berhenti sudah diatur sedemikian sehingga jika animasi sedang berjalan, lalu tombol diklik, maka animasi akan berhenti, begitu juga sebaliknya, jika animasi dalam keadaan berhenti, maka mengklik tombol akan memulai animasi. Perhatikan bahwa jika parameter oneshot dari daftar animasi diset pada posisi true, maka animasi akan berhenti setelah tereksekusi sekali. Walaupun animasi berakhir pada saat menjalankan gambar terakhir, tidak akan ada pemberitahuan yang menyatakan bahwa animasi telah selesai. Karena itu, tidak ada cara langsung untuk mengeluarkan pemberitahuan pada saat animasi selesai. Disamping itu,dengan hanya menggunakan animasi frame-by-frame maka sudah dapat menghasilkan efek visual yang bagus. Dasar Pemrograman Android Page 187 3.11.2 Layout Animation Seperti yang telah dibahas sebelumnya, animasi frame-by-frame adalah cara cepat dan sederhana untuk menambahkan efek visual ke dalam aplikasi Android, demikian pula Layout Animation. Layout Animation dapat digunakan pada ListView dan GridView, hal ini merupakan hal yang umum digunakan pada Android, selain itu animasi ini juga dapat diterapkan pada ViewGroup. Pada awal bab ini, telah ditunjukkan bagaiamana Layout Animation bekerja dengan menerapkan prinsip Tweening untuk setiap tampilan yang merupakan bagian dari layout yang beranimasi. Tweening, sebagaimana telah disebutkan sebelumnya, adalah proses di mana sejumlah properti tampilan berubah secara berkala. Selain itu ada juga matriks dengan mengubah matriks ini, maka bisa melakukan scaling, rotasi, dan translasi. Dengan mengubah transparansi dari 0 ke 1, maka dapat mencapai sesuatu yang disebut dengan alpha animasi. Pada bagian ini, akan banyak dilakukan eksperimen tentang kemampuan animation layout. Berikutnya mari mencoba untuk menambahkan animasi Tweening ke dalam List View. Berikut juga akan diperkenalkan ide interpolator dan perannya dalam animasi. Penjelasan pada SDK perihal interpolators memang agak samar, sehingga untuk mengklarifikasi interpolator maka akan ditunjukkan kode yang terkait. Berikutnya juga ada Layout Animation Controller yang berfungsi menjadi perantara antara animasi dan ViewGroup. Ada beberapa jenis animation pada dasar animasi Tweening: 1. Scale animation: merupakan jenis animasi untuk mengubah tampilan gambar menjadi lebih besar atau kecil, baik pada sumbu x atau sumbu y. Pada scale animation juga dapat ditentukan pivot point pada tempat animasi ditampilkan. 2. Rotate animation: jenis animasi yang memutar tampilan di sejumlah titik pivot. 3. Translate animation:animasi yang menampilkan pergerakan sepanjang sumbu x atau sumbu y. 4. Alpha animation: berfungsi untuk mengubah transparansi gambar. Tentukan semua nilai parameter yang terkait dengan animasi, yaitu nilai pada saat awal dan akhir animasi. Setiap animasi juga memungkinkan baik durasi sebagai argumen maupun waktu interpolator sebagai argumen. Interpolator akan dibahas pada akhir dari bagian ini, tetapi untuk sekarang, bisa diketahui bahwa interpolators menentukan laju perubahan argumen animasi Dasar Pemrograman Android Page 188 selama animasi ditampilkan. Berikutnya definisikan animasi ini sebagai file XML dalam subdirektori /res/anim. <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> <scale android:fromXScale="1" android:toXScale="1" android:fromYScale="0.1" android:toYScale="1.0" android:duration="500" android:pivotX="50%" android:pivotY="50%" android:startOffset="100"/> </set> @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setupListView(); } private void setupListView() { String[] listItems = new String[] { "Pilihan 1", "Pilihan 2", " Pilihan 3", " Pilihan 4", " Pilihan 5", " Pilihan 6", }; ArrayAdapter listItemAdapter = new ArrayAdapter(this ,android.R.layout.simple_list_item_1 ,listItems); ListView lv = (ListView)this.findViewById(R.id.list_view_id); lv.setAdapter(listItemAdapter); } Berikut tampilannya: Dasar Pemrograman Android Page 189 Gambar 3.41 Tampilan Alpha Animation File animasi berada dalam subdirektori /res/anim. Berikutnya marilah memahami arti dari file XML di atas. Di sini, perbesaran dimulai pada 1 dan tetap pada 1 di sumbu x. Ini berarti daftar item tidak akan beranimasi menjadi besar/menjadi kecil pada sumbu x. Namun, pada sumbu y, perbesaran dimulai pada 0,1 dan membesar sampai 1,0. Dengan kata lain, objek yang beranimasi mulai dari sepersepuluh ukuran normal dan kemudian tumbuh menjadi ukuran normal. Scaling akan memerlukan waktu 500 milidetik untuk selesai. Nilai startOffset mengacu pada jumlah milidetik sebelum memulai animasi. Animasi ini juga memungkinkan untuk menampilkan lebih dari satu animasi, namun intuk saat ini hanya akan ditunjukkan satu contoh saja. Nama file berikut ini adalah scale.xml, tempatkan di subdirektori /res/anim. Untuk sementara belum diperlukan untuk mengatur file ini sebagai argumen ke ListView, ListView pertama membutuhkan file XML lain yang bertindak sebagai mediator antara dirinya dan set animasi. Dasar Pemrograman Android Page 190 Berikut kode xml: <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="30%" android:animationOrder="reverse" android:animation="@anim/rotate" /> Selain itu diperlukan tempat file XML dalam subdirektori /res/anim. Berikutnya buat sebuah file XML dengan nama list_layout_controller. Dengan hanya melihat nama dari file ini, tentu sudah bisa dipastikan mengapa file ini diperlukan dan apa fungsinya. File XML menetapkan bahwa animasi dalam daftar tersebut harus dilanjutkan secara terbalik, dan bahwa animasi untuk setiap item harus dimulai setelah delay 30 persen dari total durasi animasi. File XML ini juga merujuk ke file animasi individu, scale.xml. Juga perhatikan bahwa nama file, kode menggunakan referensi sumber daya @anim/skala. <?xmlversion="1.0"encoding="utf-8"?> <!-- filename: /res/layout/list_layout.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/list_view_id" android:layout_width="fill_parent" android:layout_height="fill_parent" android:persistentDrawingCache="animation|scrolling" android:layoutAnimation="@anim/list_layout_controller" /> </LinearLayout> android:layoutAnimation adalah tag kunci, yang menunjuk ke file XML mediator yang mendefinisikan controllerlayout menggunakan tag XML layoutAnimation. Tag layoutAnimation, pada fungsinya, menunjuk ke animasi individu, yang dalam hal ini adalah Dasar Pemrograman Android Page 191 animasi skala dan didefinisikan ke dalam scale.xml.Android juga merekomendasikan pengaturan tag persistentDrawingCache untuk mengoptimalkan animasi pada saat bergulir. Untuk penjelasan lebih lanjut dapat dilihat pada dokumentasi SDK Android. Ketika meng-update file list_layout.xml, plug-in ADT pada Eclipse secara otomatis akan mengkompilasi ulang package. Apabila sekarang aplikasi dijalankan, maka akan terlihat animasi skala pada masingmasing item. Sebelumnya juga telah ditetapkan durasi 500 milidetik sehingga skala yang berubah dapat diamati dengan jelas. Sekarang mari coba bereksperimen dengan jenis animasi yang berbeda. Berikutnya mari mencoba animasi alpha. <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" /> Animasi Alpha bertanggung jawab untuk mengendalikan transparansi gambar, atau pemudaran warna. Pada contoh di bawah ini,akan diperlihatkan animasi alpha untuk hilang dan tidak terlihat sama sekali setelah 1000 milidetik. <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="30%" android:animationOrder="reverse" android:animation="@anim/alpha" /> Berikutnya adalah mencoba animasi perubahan warna gradien. <setxmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> <translateandroid:fromYDelta="-100%" android:toYDelta="0" android:duration="500" /> <alphaandroid:fromAlpha="0.0" android:toAlpha="1.0" android:duration="500" /> </set> Dasar Pemrograman Android Page 192 Perhatikan bagaimana telah ditetapkan dua animasi dalam satu animasi. Animasi akan memindahkan teks dari atas ke bawah layar. Animasi alpha akan mengubah gradien warna dari terlihat terlihat sebagai teks item turun ke dalam slot-nya. <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="30%" android:animationOrder="reverse" android:animation="@anim/transalate_alpha" /> Berikutnya adalah rotate animation. <rotatexmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:fromDegrees="0.0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:duration="500" /> Gambar 3.42 Tampilan Rotate Animation. Dasar Pemrograman Android Page 193 Gambar 3.43 Tampilan Scale Animation 3.11.3 View Animation Karena sudah melalui dua bab di atas, tentunya sekarang membuat animasi dengan animasi frame-by-frame dan layout animation sudah tidak asing lagi, maka berikutnya adalah animasi yang paling kompleks dari tiga jenis animasi di atas. Bagian ini akan dimulai dengan memberikan pengenalan singkat untuk melihat animasi. Kemudian akan ditampilkan kode untuk bereksperimen dengan animasi, diikuti dengan pandangan-contoh beberapa animasi. Kemudian akan dijelaskan bagaimana menggunakan Kamera objek berkaitan dengan animasi view. (Kamera ini tidak ada hubungannya dengan kamera fisik pada perangkat, murni sebuah konsep grafis). Dalam aplikasi grafis, matriks transformasi digunakan untuk mengubah tampilan dalam beberapa cara. Proses ini melibatkan pengambilan inputset koordinat pixel dan kombinasi warna lalu kemudian menerjemahkannya ke dalam satu set koordinat pixel dan kombinasi warna. Pada akhir transformasi, maka bisa dilihat gambar berubah dalam ukuran, posisi, orientas, atau warna. Untuk mencapai semua transformasi matematis, dapat dilakukan dengan mengambil input set koordinat dan mengalikan mereka dalam beberapa cara menggunakan transformasi matriks untuk menjadi satu set baru koordinat. Sebuah matriks yang tidak mengubah tampilan bila dikalikan disebut matriks identitas. Obyek animasi memiliki callback yang memungkinkan untuk memperoleh matriks saat melihat dan mengubahnya dalam beberapa cara sampai pada sebuah tampilan baru. Mari memulai dengan suatu Activity dimana akan ditempatkan ListView dengan beberapa item, mirip Dasar Pemrograman Android Page 194 dengan cara pada saat memulai contoh di bagian "Layout Animation". Kemudian membuat sebuah tombol di bagian atas layar untuk memulai animasi ListView saat diklik. Ketika tombol mulai animasi diklik, maka akan terlihat animasi gambar yang mengecil di tengah layar dan secara bertahap menjadi lebih besar sampai memenuhi semua layar. <?xmlversion="1.0"encoding="utf-8"?> <!-- This file is at /res/layout/list_layout.xml --> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertikal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btn_animate" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Jalankan animasi" /> <ListView android:id="@+id/list_view_id" android:persistentDrawingCache="animation|scrolling" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> Perhatikan bahwa lokasi file dan nama file yang tertanam di bagian atas dari file XML untuk referensi. Layout ini memiliki dua bagian: pertama adalah tombol yang bernama btn_animate untuk menghidupkan animasi, dan yang kedua adalah ListView, yang bernama list_view_id. Sekarang kita memiliki layout untuk Activity ini, kita dapat membuat Activity untuk menunjukkan melihat dan mengatur tombol Animasi. @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Dasar Pemrograman Android Page 195 setContentView(R.layout.main); setupListView(); this.setupButton(); } privatevoid setupListView() { String[] listItems = new String[] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", }; ArrayAdapter listItemAdapter = new ArrayAdapter(this ,android.R.layout.simple_list_item_1 ,listItems); ListView lv = (ListView)this.findViewById(R.id.list_view_id); lv.setAdapter(listItemAdapter); } privatevoid setupButton() { Button b = (Button)this.findViewById(R.id.btn_animate); b.setOnClickListener( new Button.OnClickListener(){ publicvoid onClick(View v) { animateListView(); } }); } privatevoid animateListView() { ListView lv = (ListView)this.findViewById(R.id.list_view_id); lv.startAnimation(new ViewAnimation()); } Tujuan dari contoh ini adalah untuk menambahkan animasi ke ListView. Untuk melakukan hal itu, Dasar Pemrograman Android maka diperlukan oleh class yang berasal dari Page 196 android.view.animation.Animation. Kemudian ganti method applyTransformation untuk memodifikasi transformasi matriks. Hal ini disebut ViewAnimation. public class ViewAnimation extends Animation { public ViewAnimation(){} @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); setDuration(2500); setFillAfter(true); setInterpolator(new LinearInterpolator()); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { final Matrix matrix = t.getMatrix(); matrix.setScale(interpolatedTime, interpolatedTime); } } Berikut tampilan aplikasi view animation: Dasar Pemrograman Android Page 197 Gambar 3.44 Tampilan view animation Dasar Pemrograman Android Page 198