Modul Android Ver 6 April 2014

Anda mungkin juga menyukai

Anda di halaman 1dari 146

Pengantar Mobile Programming dengan Android

Yudi Wibisono
email:yudi@upi.edu
twitter: @yudiwbs
Ilmu Komputer, Universitas Pendidikan Indonesia (http://cs.upi.edu)
versi (BETA): April 2014
Periksa versi terakhir di: http://yuliadi.com/ilkom

http://creativecommons.org/licenses/by-nc-sa/3.0/
Modul ini bebas dicopy, didistribusikan, ditransmisikan dan
diadaptasi/dimodifikasi/diremix dengan syarat: tidak untuk
komersial, pembuat asal tetap dicantumkan dan hasil modifikasi
di-share dengan lisensi yang sama.

versi April 2014

Perbaikan Modul..................................................................................................................4
Pengantar Modul..................................................................................................................4
Sekilas Android....................................................................................................................4
Fitur-fitur.............................................................................................................................5
Perbedaan dengan Aplikasi Desktop...................................................................................5
Instalasi SDK (Windows)...................................................................................................7
Aplikasi Pertama: Hello World..........................................................................................10
Menggunakan Device Android......................................................................................13
Aplikasi Kedua: Hello XXX..............................................................................................14
Widget atau View...............................................................................................................21
Text View.......................................................................................................................21
Button............................................................................................................................21
ImageButton dan ImageView........................................................................................22
EditText..........................................................................................................................24
CheckBox......................................................................................................................25
RadioButton...................................................................................................................27
ListView.........................................................................................................................29
Composite ListView..................................................................................................31
Penanganan Click pada ListView..............................................................................36
Dialog................................................................................................................................37
Toast...............................................................................................................................37
AlertDialog....................................................................................................................37
Logging..............................................................................................................................38
Layout Manager.................................................................................................................40
RelativeLayout...............................................................................................................40
TableLayout...................................................................................................................43
Frame Layout.................................................................................................................45
LinearLayout..................................................................................................................47
ScrollView.....................................................................................................................48
Kombinasi Layout.........................................................................................................50
Activity dan Intent.............................................................................................................51
Pertukaran Data antar Activity.......................................................................................54
Mengirimkan data ke activity....................................................................................54
Menerima data dari actvity yang dipanggil...............................................................55
Activity Life Cycle........................................................................................................58
Simpan dan Load Activity State................................................................................59
Fragments..........................................................................................................................63
Penambahan Fragment melalui XML............................................................................63
Penambahan Fragment secara Dinamis.........................................................................65
Komunikasi Activity Fragment.................................................................................68
Komunikasi Fragment Activity.................................................................................69
Dinamik Layout dengan Fragment................................................................................71
ActionBar...........................................................................................................................71
ActionItem.....................................................................................................................72

versi April 2014

String Resources............................................................................................................73
Icon................................................................................................................................74
Action Bar untuk Froyo.................................................................................................76
Navigation Drawer.............................................................................................................76
Menyimpan Data...............................................................................................................78
Shared Preferences.........................................................................................................78
SQLite............................................................................................................................79
Group By, Having, Order By.....................................................................................82
RawQuery..................................................................................................................83
Loop Semua Record..................................................................................................83
Mengisi ListView dengan Record.............................................................................84
File.....................................................................................................................................91
Stream........................................................................................................................91
Persiapan....................................................................................................................92
File Teks.....................................................................................................................93
Objek Stream.............................................................................................................94
Sensor................................................................................................................................98
Accelerometer................................................................................................................98
Orientasi: Yaw (Azimuth), Pitch & Roll......................................................................101
Lokasi..............................................................................................................................104
Android Location API..................................................................................................105
Google Location API...................................................................................................109
Instalasi Google Play Service..................................................................................109
Mengambil Lokasi Terakhir.....................................................................................110
Mengambil Lokasi Secara Rutin..............................................................................113
Penanganan Error.....................................................................................................116
Koneksi dengan Server....................................................................................................118
Google Map.....................................................................................................................120
Zoom............................................................................................................................122
Ubah Posisi..................................................................................................................122
Menambahkan Layer...................................................................................................123
Grafik 2D.........................................................................................................................125
Menggambar di Canvas...............................................................................................125
Todo: Canvas coordinate transformations...................................................................130
Menulis Teks di Canvas...............................................................................................130
Event Touch.................................................................................................................132
Load Image di Canvas.................................................................................................134
Manipulasi Bitmap...................................................................................................135
Animasi di Canvas dengan Asynctask.........................................................................135
Animasi di Canvas dengan Thread..............................................................................138
Animasi dengan Multibitmap......................................................................................141
Game Loop..................................................................................................................142

versi April 2014

Perbaikan Modul
Update dari versi Des 2013 ke versi Jun 2014:

Fragment: Sudah.
Google Location API (penentuan lokasi jadi bab tersendiri karena pentingnya location-aware app) Sudah

Yang ingin ditambahkan:

Koneksi dengan BlueTooth

GCM

Navigational Drawer

AsyncTask dibahas di animasi, tapi perlu yang lebih generik

Services

Notification

ShareActionProvider

SQLite: delete, update, select satu record

Google Play Game Service

Pengantar Modul
Modul praktikum ini dibuat untuk mendukung praktikum matakuliah Mobile
Programming di Program Studi Ilmu Komputer Universitas Pendidikan Indonesia (UPI).
Diasumsikan pengguna modul ini telah mengenal dasar-dasar bahasa Java dan XML.
Modul ini ditujukan sebagai pengantar dan bukan untuk referensi lengkap. Referensi
paling lengkap dan terbaru dapat dilihat di: http://developer.android.com
Sebaiknya modul ini dibaca dan dicoba secara berurutan, terutama bagi pemula. Ada
beberapa latihan di akhir materi yang sangat dianjurkan untuk dibuat. Latihan ini
mengukur sejauh mana anda telah memahami materi. Bagi dosen, idealnya memberikan
satu atau dua tugas besar (tiap tugas dikerjakan sekitar 2 bulan) yang dibuat untuk
mengaplikasikan dan mengintegrasikan keseluruhan materi.
Sebelum mulai, silahkan buka situs http://yuliadi.com/ilkom untuk memeriksa apakah
ada update untuk modul ini.

Sekilas Android
Android adalah software platform yang open source untuk mobile device. Android berisi
sistem operasi, middleware dan aplikasi-aplikasi dasar. Basis OS Android adalah kernel
Linux 2.6 yang telah dimodifikasi untuk mobile device.
Android versi 1.0 dikeluarkan tanggal 23 September 2008. Versi 1.1 adalah versi yang
pertama kali digunakan di mobile phone disusul versi 1.5 (Cupcake), 1.6 (Donut) dst.
Versi Android terakhir adalah:

versi April 2014

2.2 (Froyo), mempercepat kinerja dengan Just In Time compiler dan Chrome V8
JavaScript engine, Wi-Fi hotspot tethering dan suppport Adobe Flash.

2.3 (Gingerbread), memperbaiki user interface, soft keyboard, copy/paste features


dan support Near Field Communication (NFC).

3.0 (Honeycomb), diperuntukkan untuk tablet yang menggunakan layar lebih besar,
multicore processors dan hardware acceleration untuk grafis.

4.0 (Ice-cream sandwich), kombinasi Gingerbread and 3.0 Honeycomb. Integrasi


antara platform untuk tablet dan smartphone.

4.1 & 4.2 (Jelly-Bean), user interface yang lebih halus (project butter).

4.3: Bluetooth low energy

4.4 (Kit Kat): Low memori, immersive mode (full screen), storage framework,
printing, sensor batching, host card emulator

Untuk mengembangkan aplikasi di Android, bahasa utama yang digunakan adalah Java,
tetapi bukan dalam platform J2ME yang memiliki banyak keterbatasan. Platform yang
digunakan di Android setara dengan J2SE, dan ini merupakan kelebihan utama Android.

Fitur-fitur
Fitur-fitur utama Android yang dapat dimanfaatkan oleh pengembang app sebagai
berikut:
Database dengan SQLite.
Menulis dan membaca file di SD card.
Integrated browser berbasis WebKit engine
2D graphics library; dan OpenGL ES 2.0 untuk 3D graphics
Lokasi dan sensor: GPS, compass, gyroscope, barometer, light sensor,
accelerometer.
Renderscript untuk pemrosesan paralel memanfaatakan CPU dan GPU
Kamera, Audio capture, Jetplayer, Media support untuk MPEG4, H.264, MP3,
AAC, AMR, JPG, PNG, GIF
GSM Telephony: fasilitas telepon dan SMS.
Connectivity: USB, Bluetooth, NFC, SIP (Session Initiation Protocol, internet
telephony khusunya untuk video conference dan instant messaging) dan WiFi
Multitouch

versi April 2014

Perbedaan dengan Aplikasi Desktop


Walaupun Java yang digunakan untuk mengembangkan Android app setara dengan J2SE
ada beberapa berbedaan app Android vs app Desktop yang perlu diperhatikan:

Beragamnya ukuran layar dan resolusi.


Karakteristik device yang memiliki banyak sensor (kamera, GPS, accelometer
dsb), terhubung ke internet dan selalu dibawa pengguna membuat app Android
punya potensi di bidang baru.
Walaupun saat ini prosesor device sudah powerfull, tetapi kemampuan batere dan
memori tetap menjadi masalah. Komputasi berat, terutama yang berjalan di
background perlu memperhitungkan masalah penggunaan daya.

Instalasi SDK (Windows)


Sebelumnya pastikan JDK telah diinstall. Jika belum, Anda dapat mendownloadnya di:
http://www.oracle.com/technetwork/java/javase/downloads/
Untuk membuat app Android, diperlukan Android SDK (Software Development Kit)
yang diperoleh di http://developer.android.com/sdk sedangkan untuk IDE (Integrated
Development Environment) dapat dipilih Eclipse, Netbeans atau bahkan langsung dengan
command line dan notepad. Tapi saat ini telah tersedia instalasi untuk Windows yang
telah menyediakan semua komponen yang dibutuhkan (ADT Bundle for Windows).
Download ADT Bundle ini, dan setelah selesai ekstrak ke tempat yang anda inginkan dan
langsung dapat dijalankan karena tidak ada proses instalasi.
Salah satu file hasil ekstrak dari ADT Bundle adalah SDK Manager.exe, jalankan file
ini. Dapat dilihat bahwa versi default API yang terinstall adalah 4.4 (API19). Jika anda
terkoneksi dengan internet, anda dapat download API versi lain yang dibutuhkan.
Selanjutnya kita perlu membuat emulator smartphone android:AVD (Android Virtual
Device). Program yang akan kita buat dikomputer akan dijalankan di emulator ini.
Masih pada SDK Manager, Pilih ToolsManage AVDs. Akan muncul dialog berisi
daftar AVD kemudian klik New

Kita akan buat AVD versi 4.4. (KitKat) Isi nama, device dan target

versi April 2014

Lalu isi RAM dengan ukuran kecil terlebih dulu, dan centang Use Host GPU (jika
komputer anda memiliki GPU). Lalu tekan OK.

Pilih AVD yang baru Anda buat lalu klik Start dan kemudian Launch. Tunggu 1-5 menit
(tergantung kemampuan komputer yang Anda miliki).

Emulator ini membutuhkan waktu cukup lama dan memori yang besar. Ambil secangkir
kopi dan silahkan tunggu sampai layar berikut muncul (jika yang muncul masih tulisan
Android berkelap-kelip, tunggu). Setelah emulator dijalankan, sebaiknya jangan ditutup
lagi untuk menghemat waktu.

versi April 2014

Terutama bagi yang belum memiliki Android, Anda dapat gunakan emulator ini untuk
mengeksplorasi fitur-fitur Android.
Selanjutnya kembali ke file bundle yang telah diekstrak, terdapat direktori Eclipse.
Masuk ke direktori ini dan jalankan eclipse.exe. Akan muncul dialog untuk memilih
direktori tempat source code akan diletakkan (gambar bawah). Jika anda pernah pernah
punya project Java dengan Eclipse sebelumnya, JANGAN gunakan direktori berisi
project-project tersebut.

Lalu akan tampil window welcome seperti gambar dibawah. Close window ini
selanjutnya anda siap membuat program pertama.

versi April 2014

Tip: Jika anda menggunaka prosesor Intel, ada cara untuk mempercepat emulator
Android, anda dapat menggunakan teknologi intel VT-x. Baca: http://wp.me/p3f1j-cI
(http://yudiwbs.wordpress.com/2012/09/15/mempercepat-emulator-android/)

versi April 2014

Aplikasi Pertama: Hello World


Sesuai tradisi programmer, langkah pertama saat mencoba suatu platform adalah
membuat aplikasi hello world. Jika anda memiliki device Android, sangat dianjurkan
menggunakannya dibandingkan emulator yang lambat.
Untuk memulai, jalankan Eclipse, pilih File New Android Application Project.

Isi seperti gambar dibawah, jangan lupa ganti nama package. Package name harus unik,
aturan yang biasa digunakan adalah menggunakan nama website organisasi anda (dalam
urutan yang dibalik), ditambah dengan nama applikasi. Misalkan nama website
organisasi anda adalah yuliadi.com, maka nama package adalah: com.yuliadi.namapp.
Jika
nama
web
organisasinya
cs.upi.edu,
maka
nama
packagenya:
edu.upi.cs.yudiwbs.namaapp.
Dapat dilihat pada gambar di bawah bahwa minimum required SDK diset dengan API11
Android 3.0 (HoneyComb) karena versi ini telah mendukung ActionBar.

Selanjutnya pilih next dan next.. sampai untuk activity pilih BlankActiviy dan Next.

versi April 2014

10

Terakhir, klik Finish dan tunggu beberapa saat.

ADT akan membuatkan bagian user interface dalam format XML (activity_main.xml)
dan code untuk activity utama (MainActivity.java) (gambar bawah)

Apa itu activity? nanti akan dijelaskan lebih lebih lanjut, tapi untuk sekarang anggap
activity sebagai bagian dari app yang melakukan task tertentu (menerima input dari user,
menampilkan output dan sebagainya).
Klik actity_main.xml dapat dilihat form komponen teks bertuliskan hello world
(gambar bawah)

Sekarang coba kita lihat rinci tentang activity_main.xml. Komponen user interface untuk
app Android ini disimpan di direktori /res/layout dalam format XML.
Gambar diatas adalah graphical layout yang berisi bagaimana layout ditampilkan dan
fasilitas untuk mengedit layout secara drag-drop. Lihat ke tab bagian bawah, pilih
activity_main.xml maka dapat dilihat format XML-nya (gambar bawah). Jadi anda dapat
mengubah elemen user interface dengan dua cara: melalui graphical layout atau langsung
mengedit file xml-nya.

versi April 2014

11

Sekarang coba buka source code main activity. Klik di tab MainActivity.java atau melalui
package explorer: buka /src, package dan klik MainActivity.java (gambar bawah)

Dapat dilihat source code yang dibangkitkan ADT

Jalankan project dengan mengklik icon run (gambar bawah) atau ctrl-F11 dan pilih
Android Application.
Tunggu emulator dilaunch jika emulator telah ditutup
sebelumnya .

Lihat emulator maka akan akan muncul aplikasi berikut

versi April 2014

12

Selamat! Anda telah menjalankan app pertama anda. Jangan tutup emulator ini, Eclipse
selanjutnya akan menggunakan emulator yang sudah terbuka ini sehingga tidak perlu
menjalankan yang baru.
Menggunakan Device Android
Menggunakan emulator memiliki banyak kelemahan. Emulator menggunakan banyak
memori dan lambat. Cara yang lebih ideal adalah menggunakan device Android yang
sesungguhnya.
Pertama kita harus aktifkan developer options, untuk JellyBeans dan Kitkat, cara
mengaktifkannya sebagai berikut:
1. Masuk ke settings, scroll down ke paling bawah, tap About Phone.
2. Scroll ke bawah lagi, lalu tap Build Number sebanyak tujuh kali. Saat tap ke-4
akan muncul pesan 'You are 3 steps away from being a developer' dan pada tap
ke-7 akan muncul pesan selamat.
Setelah developer options aktif, kita akan mengaktifkan USB debugging. Masuk ke
Settings scroll paling bawah Developer Options. Check dua pilihan seperti gambar
dibawah. USB Debugging dan Stay Awake agar device tidak sleep selama terhubung
dengan komputer.

versi April 2014

13

Device yang muncul di windows explorer belum tentu sudah terhubung dengan Android
SDK! Untuk mengecek apakah device terhubung, dapat dijalankan ADB (Android
Debug Bridge). Jalankan command line /[direktorisdk]/sdk/platform-tools/adb devices
(gambar bawah). Perintah ini akan menghasilkan device yang terhubung dengan
komputer. Salah satu alasan tidak terhubung adalah tidak tersedianya driver, jadi install
driver untuk koneksi USB sesuai dengan merk smartphone.

Selanjutnya kembali ke Eclipse, compile, akan muncul pesan seperti gambar bawah. Pilih
running Android Device. Jalankan dan dapat dilihat app HelloWorld akan dijalankan pada
device Android Anda.

Aplikasi Kedua: Hello XXX


Selanjutnya kita akan memodifikasi program ini dan menambahkan masukan nama dari
user, lalu setelah user menekan tombol, akan keluar Hello, [nama]. Terimakasih
Pertama, melalui project explorer kembali pilih activity_main.xml yang berada di
res/layout (gambar bawah).

Pilih tab Graphical Layout

versi April 2014

14

Komponen-komponen user interface yang berada di bagian kiri, sering disebut widget
atau view.
Pilih pembesar untuk lebih jelas melihat komponen user interface (gambar bawah)

Kemudian pilih widget TextField, pilih yang paling atas (plain text), lalu drag ke dalam
form, geser-geser sehingga hasilnya seperti gambar bawah. Jika posisi menjadi
berantakan jangan khawatir. Layout Android tidak mengenal posisi eksak, karena
memang tidak cocok untuk Android yang mempunyai sangat banyak variasi display.
Nanti kita akan belajar layout yang lain yang lebih cocok untuk model form seperti ini.

Lalu drag button di Form Widget, dan letakkan disebelah kanan text field. Jika button
tidak terlihat, klik panah bawah di bagian form widget (gambar bawah)

Terakhir, drag teks hello world dari tengah ke dekat button.

versi April 2014

15

Save, Coba run (ctrl-F11) untuk melihat hasil tampilan dari program ini. Jangan lupa,
jangan tutup emulatornya, supaya tidak menunggu lama saat run berikutnya. Sekarang
kita akan menambahkan aksi yang akan dijalankan saat button diklik.
Sekarang karena kita akan membuat code yang saat button di-klik menangkap apa yang
diketikkan pengguna dan menuliskannya di TextView. Untuk itu setiap komponen perlu
diberi nama.
Kembali ke activity_main.xml. Klik Button kemudian lihat window properties yang
berada di sebelah kanan, ganti Text dengan Sapa dan id dengan bSapa (gambar
bawah). Saat id diganti maka ada pesan untuk mengupdate semua kemunculan id, jawab
ini dengan Yes. Kemudian muncul window Rename Resource dan jawab ini juga
dengan OK. Cara ini akan membuat semua kemunculan id ini di activity_main akan
otomatis diganti. Ini akan lebih mudah dibandingkan harus mengganti secara manual file
xml.

Lakukan hal yang sama untuk EditText, ganti id dengan etNama. Kemudian textview,
ganti id dengan tvSalam.

versi April 2014

16

Coba lihat XML-nya, maka semua Id telah diganti (gambar bawah). Ini kelebihan
mengganti nama id menggunakan property.

Tip: untuk merapikan XML tekan ctrl-shift-F.


Sekarang kita akan mengeset agar saat button diklik, method yang diinginkan akan
dipanggil. Set atribut android.onClik pada button dengan nama method yang akan
menangani event tersebut (bSapaClick).

versi April 2014

17

Penting: setelah update XML, tekan save (ctrl-s). Ini disebabkan file R.java (di
direktori /gen) yang berisi semua Id dan digenerate secara otomatis dapat tidak terupdate
jika file xml tidak di-save secara eksplisit.
Sekarang kita perlu menambahkan code agar saat tombol diklik app akan mengeluarkan
respon.
Melalui package explorer, kembali ke activity utama (MainActivity.java).

Kemudian buat satu method baru bSapaClick. Pastikan nama method sama dengan
yang dicantumkan di activity_main.XML. Nama yang tidak sama akan menyebakan
error saat program dijalankan.

versi April 2014

18

Tambahkan impor class yang dibutuhkan. Salah satu cara yang paling mudah adalah
dengan shortcut keyboard ctrl-shift-O (huruf o bukan angka nol). Cara lain dengan
mengklik gambar x merah di sebelah kiri, lalu pilih impor (gambar bawah).

Tip: Jika id tidak dikenali seperti R.id.etNama, R.id.tvSalam dan seterusnya, buka
kembali activity_main.xml lalu tekan ctrl-S (save)
Jalankan program (ctrl-F11), perhatikan tab Console di bagian bawah untuk memonitor
proses emulasi. Isi teks dan tekan tombol.

Cara ini paling sederhana, tetapi programmer harus memastikan nama method pada XML
sama dengan nama method di program. Jika nama method tidak sama, tidak akan muncul
kesalahan pada saat program dicompile, tapi akan menyebabkan kesalahan pada saat
runtime (saat button diklik). Alternatif lain adalah dengan menggunakan listener seperti
code dibawah.

versi April 2014

19

Listener juga berguna dalam fragment karena atribut onClick hanya dapat digunakan
pada Activity.
Mana yang lebih baik? menggunakan atribut onClik atau dengan listener? itu tergantung
dari selera programmer dan standard code yang digunakan.

versi April 2014

20

Widget atau View


Pada modul sebelumnya kita telah menggunakan input box, button dan label. Komponen
user interface ini disebut widget. Beberapa widget dasar adalah: TextView, Button,
Image, EditText, CheckBox, RadioButton, ListView.
Setiap widget memiliki property atau atribut yang mengatur bagaimana widget itu
ditampilkan, seperti tinggi dan lebar widget. Property ini dapat diset melalui xml layout,
property editor atau melalui program. Beberapa widget memiliki beberapa event yang tertrigger berdasarkan aksi dari pengguna, misalnya event click pada button.
Detil property dan event untuk setiap widget dapat dilihat di:
http://developer.android.com/reference/android/widget/package-summary.html (scroll
sedikit ke bawah, di bagian classes)
Berikut akan kita bahas beberapa widget yang terpenting. Silahkan buat project baru.
Text View
TextView digunakan untuk menampilkan label teks. View ini sudah kita gunakan
Beberapa contoh property dari TextView adalah android:textSize, android:textStyle,
android:textColor. Coba tambahkan textview standard dengan atribut dibawah.

Hasilnya:

Catatan: pada atribut textSize, direkomendasikan menggunakan ukuran sp. sp merupakan


singkatan dari scaled-pixel yang memperhitungkan kepadatan resolusi dan juga
preferensi ukuran font dari pengguna.

versi April 2014

21

Button
Button merupakan turunan dari TextView sehingga yang berlaku di textView juga berlaku
di button. Tambahan property yang penting adalah onClick

Hasilnya (perhatikan penggunan fill_parent untuk atribut layout_width):

Catatan: dp yang digunakan sebagai satuan panjang merupakan singkatan dari densityindependen pixel. Nilai pixel untuk 1 dp berubah-ubah sesuai dengan resolusi. 1 dp pada
resolusi 160 pixel berarti 1 pixel. Jika resolusinya 320 pixel, maka 1 dp = 2 pixel
demikian seterusnya.
ImageButton dan ImageView
ImageButton adalah turunan dari button, gunakan widget ini jika Anda ingin
menggunakan image sebagai pengganti tulisan pada button. Sedangkan ImageView dapat
digunakan untuk menampilkan image.
Image yang akan ditampilkan dalam button diletakkan di direktori /res sesuai dengan
resolusinya
/[project]/res/drawable-ldpi
/[project]/res/drawable-mdpi
/[project]/res/drawable-hdpi
/[project]/res/drawable-xhdpi
/[project]/res/drawable-xxhdpi
res merupakan singkatan dari resource, file-file yang berada di dalam direktori /res
disebut dengan project resources.

versi April 2014

22

ldpi digunakan untuk untuk device dengan layar low density atau resolusi rendah 120dpi
(dot per inch), mdpi untuk medium (160dpi) , hdpi untuk high density (240dpi) dan xhdpi
untuk ekstra high density (320dpi). Sedangkan xxhdpi untuk resolusi 480dpi. Saat ini
sudah jarang device dengan resolusi ldpi.
Coba buka direktori tersebut, terdapat icon launcher untuk masing-masing resolusi (iclauncher.png), dapat dilihat ukuran yang berbeda untuk setiap resolusi. Jadi untuk hasil
yang maksimal, untuk setiap image yang akan anda gunakan harus disediakan 4 image
untuk setiap resolusi (mdpi sampai dengan xxhdpi). Hal ini untuk mencegah gambar yang
digunakan terlihat pecah atau terlalu kecil pada device dengan resolusi berbeda.

Misalnya kita akan menambah button dan image view. Sebagai sumber gambar kita akan
menggunakan icon standard yang sudah ada direktori drawable. Di window palette, pilih
images & media lalu Image View (paling kiri).

Pilih ic_launcher

TBD hasilnya
Coba lakukan yang sama untuk widget Image Button sehingga tampilannya akan
seperti ini

versi April 2014

23

Coba jalankan dan klik terutama untuk button-nya.


Untuk menambahkan image bersama-sama dengan teks pada button, dapat digunakan
komponen button (bukan ImageButton) lalu set atribut drawableLeft dengan image yang
diinginkan.
Coba tambah button, dan isi drawableLeft.

dan hasilnya

Coba ganti drawableLeft dengan drawableRight, drawableTop atau drawableButtom.


EditText
EditText digunakan untuk menerima input dari pengguna. Pada palette telah disediakan
berbagai jenis EditText, silahkan dicoba satu persatu dan perhatikan XML yang
dihasilkan.

versi April 2014

24

CheckBox
User dapat memilih lebih dari satu pilihan dengan checkbox. Pada palette, Checkbox
ada di bagian FormWidgets.

Coba tambahkan dua checkboxs lalu set atribut id dan text melalui window property:

Sehingga hasilnya

Tambahkan Button dan TextView di form untuk menampilkan hasil pilihan user.
Sehingga tampilannya akan seperti ini.

Sedangkan XML-nya akan seperti ini, anda dapat langsung mengedit file XML ataupun
melalui window property. Jangan lupa atribut onClick:

versi April 2014

25

Sedangkan contoh program untuk mendapatkan nilai suatu checkbox di check atau tidak
adalah sebagai berikut.
Tambahkan di activity code method klikHasil sebagai berikut, perhatikan penggunaan
isChecked untuk mengambil nilai apakah user meng-check pilihan:

versi April 2014

26

Latihan CheckBox:
Buat soal berikut yang penggunanya dapat memilih lebih dari satu:
-------------------------------------------------------------------------------1. Manakah kota dibawah ini yang merupakan ibu kota propinsi?
Bandung
Bogor
Banjarmasin
ini button
Bontang
Periksa Nilai
Nilai anda: [ditampilkan setelah tombol periksa nilai diklik]
-------------------------------------------------------------------------------Jawaban yang benar adalah Bandung dan Banjarmasin. Setiap jawaban
benar bernilai 10, tetapi setiap jawaban yang salah akan dikurangi 5. Jadi jika
pengguna menjawab Bandung, Bogor dan Banjarmasin dan maka
pengguna mendapat nilai 20 5 = 15. Tampilkan nilai ini.
Catatan: input dari method setText adalah teks, sehingga nilai integer harus
dikonversi terlebih dulu menjadi teks. Gunakan Integer.toString(intNilai).

RadioButton
Pada radioButton, hanya satu pilihan yang boleh aktif (mutual exclusive) di dalam satu
group yang disebut radioGroup. Modifikasi program checkbox diatas, tambahkan radio
group (bukan radiobutton) yang ada di Form Widget

Hasilnya:

Tambahkan button dan textview, lalu gunakan property untuk mengedit sehingga hasilnya
seperti berikut. Ganti id RadioGroup dengan rgJenisKel, radiobutton dengan
rbLaki dan rbPerempuan dan id TextView dengan tvHasilRadio. Tambahkan
property onClick pada button dengan nama klikHasilRadio

versi April 2014

27

Catatan: Anda dapat mengeset atribut android:orientation pada RadioGroup menjadi


horizontal agar radio button tersusun secara mendatar.
Jangan lupa save. Kemudian code saat tombol diklik adalah sebagai berikut. Perhatikan
pengunaan getCheckRadioButtonId yang mengambil idRadio yang dipilih oleh
pengguna:

Catatan: Menggeser radio button dapat berakibat radiobutton tidak berada lagi di dalam
radio group. Pada XML, radiobutton harus berada di dalam radiogroup.

versi April 2014

28

Latihan:
Buat soal berikut yang penggunanya hanya dapat memilih tepat satu:
-------------------------------------------------------------------------------1. Sebutkan ibu kota propinsi Sulawesi Tenggara?
Samarinda
Kendari
Palu
Makasar
ini button
Nilai anda: [ditampilkan setelah tombolPeriksa
periksa Nilai
nilai diklik]
-------------------------------------------------------------------------------Jawaban yang benar adalah Kendari. Jika pengguna memilih pilihan yang benar akan mendapat nilai 10, sedangkan jika menjawab salah maka akan

ListView
List view adalah widget untuk menampilkan data dalam bentuk list yang dapat di-scroll.
Karena ukuran layar smartphone terbatas, listview merupakan salah satu widget
terpenting dan paling sering digunakan untuk menampilkan kelompok informasi.
ListView dapat berbentuk sederhana sampai kompleks. Beberapa contoh

versi April 2014

29

Kita akan mulai dengan membuat list sederhana seperti gambar di bawah:

Pertama, buat project baru lalu pilih Composite dan tambahkan ListView di
activity_main.xml

Ganti id list view dengan listAngka


Di activity utama, tambahkan code sebagai berikut:
public class MainActivity extends Activity {
private String[] items = {"satu", "dua", "tiga", "empat"};
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listAngka = (ListView) findViewById(R.id.listAngka);
//set warna abu2, karena default font adalah putih
listAngka.setBackgroundColor(Color.LTGRAY);

/*buat adapter
3 parameter:
- context: diambil dengan getApplication()
- layout listview: disini kita menggunakan yang sudah ada
- datanya: items
*/
adapter = new ArrayAdapter<String>
(getApplication(),android.R.layout.simple_expandable_list_item_1,items);
listAngka.setAdapter(adapter);

versi April 2014

30

Coba jalankan.
Pada code di atas, dibuat adapter berisi string untuk mengisi list. Sedangkan
R.layout.simple_expandable_list_item1 adalah layout standard yang disediakan
Android.
Bagaimana mengupdate isi listview saat program sedang berjalan?
Untuk mengupdate data pada contoh diatas, nilai array dapat langsung diubah lalu
panggil method adapter.notifyDataSetChanged()untuk merefresh tampilan. Sebagai
contoh, kita akan membuat button yang saat diklik akan mengubah item pertama:
Tambahkan button diatas listview

Tambahkan event onClick bernama klikButton dan kode seperti berikut:

Composite ListView
Listview juga dapat digunakan untuk menampilkan struktur yang lebih rumit. Contoh
berikut memperlihatkan listview dengan isi yang kita tentukan sendiri.

Untuk membuatnya, pertama buat project baru. Tambahkan ListView seperti pada contoh
sebelumnya. Ganti id dengan listJudul.

versi April 2014

31

Kemudian kita akan buat layout untuk setiap baris pada ListView yang berisi judul dan
keterangan. Pilih project pada project explorer, lalu klik kanan Android Tools
New Resources File (gambar bawah)

Catatan: alternatif lain membuat layout XML, klik kanan project new Android
XML File.
Pilih resource type Layout. Beri nama file row.xml, pilih root element LinearLayout,
XML akan dibuat di dalam direktori /res/layout. File row.xml ini akan menentukan
layout dari setiap baris pada listview.

Pada row.xml yang baru digenerate tambahkan widget LargeText dan TextView (gambar
bawah). Ganti Id kedua komponen itu. LargeText dengan tvJudul dan TextView dengan
tvKeterangan.

versi April 2014

32

Pada contoh di atas hanya digunakan dua widget (LargeText dan TextView), tapi
sebenarnya apapun dapat dimasukkan di dalam layout ini. Misalnya Button, ImageView
dan lainnya. Ini memungkinkan kita membuat ListView dengan isi yang kompleks.
Sekarang buat class untuk yang menampung data judul dan keterangan. Pada project
explorer, pilih /src/[package], klik kanan new Class

Beri nama DataList

Berikut isi dari DataList. Class ini akan berisi data yang akan muncul di setiap baris.

versi April 2014

33

Selanjutnya kita akan buat adapter untuk list. Fungsinya untuk mengisi setiap row
dengan isi objek DataList.
Buat class dengan cara yang sama dengan sebelumnya (klik /src/[package], klik kanan,
new class), beri nama DataAdapter, jadikan class ini turunan dari kelas ArrayAdapter.
Klik browse di dialog saat membuat class di bagian superclass (gambar bawahh)

Ketik Array, maka akan muncul ArrayAdapter, pilih item tersebut (gambar bawah)

Isi class DataAdapter adalah sebagai berikut. Pada method getView, parameter pos
adalah indeks baris. Perhatikan pengisian tvJudul dan tvKeterangan dengan data sesuai
indeks.

versi April 2014

34

Terakhir, di activity utama (MainActivity.java) tambahkan kode berikut:

Jika dijalankan, hasilnya akan seperti ini:

Latihan:
Buat program dengan tampilan seperti berikut, saat tombol diklik, maka isi list
akan bertambah sesuai dengan nim dan nama. Tip: gunakan
adapter.notifyDataSetChanged() untuk merefresh data.

versi April 2014

35

Penanganan Click pada ListView


Listview sering digunakan untuk menampilkan data berbentuk master-detail. Jika di-tap
suatu baris maka akan ditampilkan detil pada layar terpisah. Listview juga dapat
digunakan untuk menampilkan menu.
Untuk menangani tap pada listview, gunakan method setOnItemClickListener
Contoh berikut akan menampilkan dialog singkat jika baris ditekan, judul pada baris juga
akan berubah menjadi warna merah. Berdasarkan kode pada contoh listview sebelumnya,
tambahkan kode berikut (bagian yang dilingkari). Penjelasan tentang Toast ada di sub bab
berikutnya.

Ada empat parameter untuk onItemClick:


Parent
View
Positio
n
id

versi April 2014

AdapterView (view parent yang menampung semua row)


View baris yang ditap, digunakan untuk mengambil view yang berada di
dalam row yang kemudian dapat dimanipulasi.
Posisi (indeks) dari baris yang di tap, bisa digunakan untuk mengambil data
yang tersimpan di array, ArrayList atau yang lain.
Id dari row.

36

Dialog
Seringkali app perlu menyampaikan pesan sementara kepada pengguna, misalnya jika
menampilkan informasi, melaporkan kesalahan atau memperlihatkan proses yang
memakan waktu lama.

Toast
Toast digunakan untuk menampilkan pesan yang setelah muncul kemudian akan
menghilang dengan sendirinya tanpa interaksi dengan pengguna. Fokus juga tetap pada
aplikasi dan tidak berpindah ke Toast. Kelebihan Toast adalah mudah untuk dibuat,
sedangkan kelemahannya adalah pengguna dapat saja tidak melihat pesan yang
ditampilkan Toast.
Untuk mencobanya, buat project baru, tambahkan satu button, beri label Toast dan
kode berikut adalah event saat button diklik:
public void toastClick(View v) {
Toast t = Toast.makeText(this, "Toast tampil cepat",Toast.LENGTH_SHORT);
t.show();
Toast t2 = Toast.makeText(this, "Toast tampil lama",Toast.LENGTH_LONG);
t2.show();
Toast t3 = Toast.makeText(this, "Toast tampil ditengah",Toast.LENGTH_SHORT);
t3.setGravity(Gravity.CENTER|Gravity.CENTER, 0,0);
t3.show();
}

AlertDialog
Jika yang diinginkan adalah dialog yang muncul dan harus ditutup secara manual oleh
pengguna maka dapat digunakan AlertDialog. AlertDialog dapat menampilkan tiga
button.
Tambahkan button pada program sebelumnya, beri label AlertDialog. Tambahkan code
berikut untuk event onClick.

versi April 2014

37

Hasilnya akan seperti ini:

Selain setMessage dan setPositiveButton, dapat digunakan method setTitle, setIcon


untuk mengeset judul dan icon message dan SetNeutralButton (button tengah) dan
SetNegativeButton (button kanan). Berikut contohnya

Logging
Fitur logging digunakan untuk memberikan keterangan apa yang sedang terjadi pada app.
Manfaat utama fitur ini adalah untuk mendebug app.
Sebagai contoh, buka project yang pernah anda buat sebelumnya. Lalu pada bagian
MainActivity onCreate tambahkan log sebagai berikut. yw adalah tag dan dapat diganti
dengan string apapun.

versi April 2014

38

Buka tab logcat dan jalankan program

Terlihat banyak message di dalam logcat, untuk memfilternya sesuai dengan tag yang
kita tentukan sebelumnya, tambahkan filter (gambar bawah). Nama filter dapat diisi
bebas.

Fitur filter yang lain adalah memfilter berdasarkan jenis lognya (verbose sampai dengan
error), terutama untuk jenis error.

Pada contoh diatas kita menggunakan Log.i (info), selain itu dapat digunakan method
Log.v(), Log.d(), log.w() dan Log.e() untuk verbose, debug, warn dan error.

versi April 2014

39

Tips: untuk tag, dianjurkan menggunakan variabel yang berada di class activity (code
dibawah)
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"program dimulai");
}

Layout Manager
Untuk meletakan komponen (view) pada layar, android menggunakan layout manager.
Karena ukuran layar device Android sangat beragam, tidak ada peletakan posisi widget
secara eksak per pixel.
Terdapat empat jenis layout manager yang memiliki fungsi
masing-masing.
LinearLayout, TableLayout, RelativeLayout dan FrameLayout. Berikut akan dibahas
lebih rinci untuk setiap layout.

RelativeLayout
RelativeLayout mengatur posisi secara relatif berdasarkan posisi widget yang lain atau
parentnya. Sebagai contoh, dua widget pada gambar di bawah. EditText posisinya relatif
terhadap textView nama.

Contoh deklarasinya adalah sebagai berikut:

versi April 2014

40

Untuk layout_width dan layout_height ada dua pilihan: match_parent (view berusaha
sebesar parent) dan wrap_content (view hanya berusaha sebesar content yang berada di
dalamnya). Sedangkan padding menyatakan jarak antara pinggir layar dengan komponen.
Perhatikan penggunaan atribut layout_toRightOf yang menyatakan bahwa EditText
berada disebelah kanan label. Sedangkan atribut layout_baseLine digunakan agar
TextView dan EditText aligned. Jika layout_baseLine dihapus efeknya akan sebagai
berikut (Text View terlalu tinggi posisinya):

Beberapa atribut lain yang mengatur posisi widget dibandingkan dengan widget lain
adalah:

android:layout_above
android:layout_below
android:layout_toLeftOf
android:layout_toRightOf.

Untuk mengatur posisi ada tambahan lima atribut: android: layout_alignTop,


android:layout_alignBottom, android:layout_alignLeft, android:layout_alignBaseline
Contoh jika kita ingin menambahkan button sehingga posisinya sebagai berikut:

versi April 2014

41

Maka deklarasi buttonnya adalah sebagai berikut:

Artinya button tersebut dibawah dan disebelah kanan EditText.


Widget juga dapat diatur berdasarkan gravity android:layout_gravity ada beberapa pilihan
untuk gravity ini: left, right, center_horizontal, center_vertical, bottom, top. Gravity ini
juga berlaku untuk layout manager yang lain. Berikut adalah contohnya:

Hasilnya:

Silahkan bereksperimen dengan berbagai setting atribut layout.

versi April 2014

42

TableLayout
Untuk memilih layout manager, selain dengan cara manual dapat juga ditentukan
membuat layout (File New Other Android XML Layout File). Saat muncul
dialog berikut, pilih Root Element sebagai TableLayout.

TableLayout meletakan komponen dalam bentuk tabel (baris dan kolom), mirip seperti
Table yang digunakan di HTML.
Pengguna mendefinisikan baris dengan tag
<TableRow> dan sistem secara otomatis mendefinisikan kolomnya. Contoh deklarasi
berikut:

versi April 2014

43

Hasilnya adalah sebagai berikut. Bayangkan sebagai sebuah tabel dengan dua kolom dan
dua baris.

Kolom 0

Kolom 1

Misalnya kita ingin agar


EditText sampai ke bagian belakang, maka tambahkan
android:stretchColumns="1" pada TableLayout. Maka kolom 1 akan terisi penuh.

versi April 2014

44

Hasilnya:

Untuk menambahkan widget di kolom tertentu, gunakan android:layout_column.


Misalnya kita akan menambahkan TextView di kolom 1 (ingat kolom dimulai dari 0). Ini
bisa dilakukan dengan menggunakan atribut android:layout_column. Tanpa atribut ini,
TextView akan muncul di kolom 0

Hasilnya sebagai berikut:

Frame Layout
Framelayout digunakan untuk menampilkan satu komponen dalam satu layar. Jika ada
lebih dari satu widget, maka akan ditampilkan secara bertumpuk, walaupun posisi widget
dapat diatur dengan gravity. Kita bisa menambahkan layout lain sebagai child di dalam
frame layout.
Contoh untuk deklarasi berikut menampilkan dua ImageView (pastikan file image telah
disimpan di direktori [project]/res/drawable-hdpi, [project]/res/drawable-ldpi dan
[project]/res/drawable-mdpi )

versi April 2014

45

Hasilnya gambar akan bertumpuk seperti ini.

Catatan: layout_weight adalah rasio antara view. Misalnya ada dua widget, widget
pertama ukurannya harus layar dan sisanya layar. Maka set layout_weight widget
pertama dengan 3 dan widget kedua dengan 1. Height atau widht perlu diset 0px.
TBD contohnya

versi April 2014

46

LinearLayout
Sesuai dengan namanya, linear layout menyimpan widget dalam satu baris atau satu
kolom (tergantung orientasinya).
Jika orientasinya vertical (android:orientation="vertical") maka hasilnya akan seperti ini

Sedangkan jika orientasinya horizontal (android:orientation="horizontal"), maka hasilnya


akan seperti ini.

Berikut adalah contoh linear layout dengan satu textview dan satu button.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>

versi April 2014

47

ScrollView
Dengan scrollview, layout seolah-olah memiliki layar yang lebih luas. Pengguna dapat
melakukan scroll. Scrollview hanya mempunyai satu child dan umumnya adalah
LinearLayout.
Scrollview hanya dapat melakukan vertical scrolling, gunakan
HorizontalScrollView untuk layout yang dapat discroll secara horizontal.
Jangan gunakan Listview bersama layout ini karena listview telah memiliki mekanisme
scrolling tersendiri.
Berikut adalah contoh scrollview yang menghasilkan layout seperti ini yang dapat
discroll. Dua button teratas menggunakan RelativeLayout yang disisipkan dalam
ScrollView. Ini juga contoh penggabungan antara dua layout.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scroller"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />

versi April 2014

48

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/button1"
android:text="Button" />
</RelativeLayout>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
</ScrollView>

versi April 2014

RelativeLayout didalam
LinearLayout.
Didalamnya ada dua
button.

Beberapa button agar


scroll terlihat.

49

Kombinasi Layout
Kita bisa mengkombinasikan beberapa layout dalam satu activity. Contoh berikut
menggunakan linearlayout yang memiliki dua anak yaitu relativelayout dan tablelayout.
Relative
layout
dengan dua
TextView

TableLayout
dengan tiga
kolom dan tiga
baris

versi April 2014

50

Latihan Layout
Berdasarkan hasil latihan activity-intent, pada layar2 dan layar3, tambahkan
layout yang tepat agar tampilan widget rapi.

Activity dan Intent


Dalam materi sebelumnya, selalu digunakan satu activity. Tentu saja sebuah applikasi
sering membutuhkan lebih dari satu activity. Activity adalah komponen terkecil
penyusun Android App yang berisi satu kegiatan yang dapat dilakukan oleh pengguna.
Untuk menghubungkan antar activity dapat digunakan intent. Intent adalah fasilitas
untuk menghubungkan satu activity ke activity yang lain, baik untuk activity di dalam
app yang sama maupun antar app yang berbeda. Intent juga digunakan untuk notifikasi
event misalnya saat SD card dimasukkan, SMS masuk dan lain-lain.
Untuk lebih memahami activity dan intent, sekarang coba buka salah satu app android
yang telah dibuat sebelumnya, lalu pada project explorer pilih AndroidManifest.xml. File
XML ini berisi property aplikasi, termasuk di dalamnya activity dan intent.

versi April 2014

51

Klik xml-nya dibagian bawah

Lihat tag activity, dapat dilihat ada satu activity dengan property nama dan label.
Selain itu terdapat tag intent-filter yang digunakan untuk memfilter intent yang dapat
dihandle activity. android.intent.categori.LAUNCHER menyatakan activity ini adalah
initial activity yang dapat dipanggil langsung oleh launcher sedangkan
intent.action.MAIN menyatakan activity ini adalah initial activity tanpa data input dan
tidak menghasilkan output.

Sekarang kita akan membuat contoh app yang memiliki dua activity.
Pertama buat project baru. Kemudian langsung buat activity kedua, caranya buat class
baru: di project explorer klik package, klik kanan New Class. Beri nama class ini
ActivityDua dan pastikan superclass kelas ini adalah android.app.Activity (gambar
bawah)

Sekarang kita perlu menambahkan activity ini di AndroidManifest.xml. Isi atribut name
dengan nama class lengkap dengan nama package dan label (gambar bawah)

versi April 2014

52

Penting: Tanpa menambahkan activity ke dalam AndroidManifest.xml, akan terjadi


force close saat program dijalankan.

Sekarang kembali ke activity utama (MainActivity), tambahkan button di layout


activity_main.xml, isi atribut onClick dengan clickButton. Buat implementasi method
clickButton sebagai berikut, perhatikan pengunaan class Intent:

Dari kode diatas dapat dilihat bahwa intent merupakan struktur data (objek) yang
dilempar sebagai paramater ke method startActivity.
Jika program dijalankan hasilnya akan seperti ini. Terlihat label pada ActivityDua yang
disimpan di dalam AndroidManifest.xml akan menjadi title.

Terlihat ActivityDua masih polos tanpa layout. Sekarang kita akan membuat layout untuk
activity tersebut. Ini mirip saat membuat layout baris pada ListView.
Untuk membuat file layout, pilih project di project explorer, klik kanan, AndroidTools
New Resources File. Pilih resource type Layout. Beri nama file activity_dua.xml, pilih
root element LinearLayout (gambar bawah)

versi April 2014

53

Tambahkan widget Large Text ke dalam layout, beri nama tvDua dan save.

Sekarang kita perlu meload layout ini saat activity kedua dijalankan. Buka class
ActivityDua dan tambahkan kode dibawah dan coba jalankan.

Pertukaran Data antar Activity


Pada contoh sebelumnya, activity kedua dipanggil tanpa ada data yang dikirimkan dari
activity utama. Sekarang kita akan belajar bagaimana cara mengirim dan menerima data
antar activity.

Mengirimkan data ke activity


Kita akan memodifikasi contoh pada app sebelumnya (app dengan dua activity).
Pada MainActivity, ubah kode sebagai berikut, perhatikan method putExtra untuk
menambahkan data yang akan dikirim.

Sedangakan di ActivityDua tambah kode sebagai berikut untuk menerima data. Method
onStart ini akan otomatis dipanggil saat activity mulai dijalankan setelah onCreate. Coba
jalankan kembali app ini.

versi April 2014

54

Menerima data dari actvity yang dipanggil


Untuk mengirimkan dan menerima data dari activity, dapat digunakan
startActivityForResult.

method

Sebagai contoh, kita akan membuat activity yang memanggil activity lain, pengguna
mengisi data pada activity tersebut dan mengirimkannya kembali ke activity utama. Kita
akan memodifikasi program sebelumnya.
Catatan: jika anda mau program sebelumnya tidak hilang, anda dapat menduplikasi
project dengan mencopy-paste project tersebut pada package explorer.
Sekarang kembali ke activity utama MainActivity, gunakan method putExtra untuk
menambahkan data ke intent. Pada startActivityForResult terdapat parameter angka 99
(silahkan ganti dengan angka atau konstanta apapun). Paremeter ini diperlukan karena
satu activity bisa mengirimkan banyak intent dan diperlukan cara untuk membedakan
antara satu intent dengan intent yang lain.
Method onActivityResult akan dipanggil saat activity yang dipanggil telah selesai.

versi April 2014

55

Selanjutnya kita akan menambahkan widget editText pada activity dua yang dapat diedit
oleh pengguna dan hasilnya akan dikirimkan kembali ke activity utama. Buka
res/layout/activity_dua.xml. Tambakan satu editText dan satu button. Beri nama etNama
dan tambahkan android:onClick="clickButtonActDua" di button.

Sekarang kita akan membuat kode di activitydua yang akan mengisi editText dengan data
yang dikirim dari activity utama dan setelah button ditekan mengirimkan hasil update ke
activity utama. Buka file ActivityDua.java dan tambahkan kode berikut:

Jika dijalankan hasilnya sebagai berikut

versi April 2014

56

Latihan Activity-Intent 1
Buat activity utama berisi nama, alamat, telp. Saat button Edit ditekan, maka
data yang ada di activity utama dikirim ke activity kedua, dan user diberi
kesempatan untuk mengedit data tersebut. Setelah button simpan ditekan maka
layar akan kembali ke activity utama dan data di activity utama harus terupdate.

Latihan Activity-Intent 2
Menggunakan listview (layar1), tampilkan daftar nama mahasiswa. Pengguna
dapat men-tap nama (baris), dan kemudian app akan menampilkan informasi
yang lebih detil berisi NIM, NAMA, ALAMAT dan NOHP (layar2). Pada layar
informasi detil (layar2) tersebut ada button EDIT yang jika diklik akan
membawa ke layar ketiga yang berisi editText untuk mengupdate data. Hasil
update akan muncul baik di layar1 dan layar2

versi April 2014

57

Activity Life Cycle


Pada contoh sebelumnya, kita telah menggunakan lebih dari satu activity. Setiap activity
memiliki siklus seperti gambar dibawah. Saat pertama kali dijalankan activity akan
berada dalam status active. Ketika user pindah app atau menjalankan activity lain maka
status dapat berubah menjadi paused atau stopped. Setelah itu app bisa kembali active
(user membuka kembali) atau di-destroy oleh Android (memori habis).
Kita dapat menangani setiap fase dari activity. Ini berguna misalnya untuk app game,
pada saat activity berubah dari active menjadi paused, maka game juga harus otomatis
dipaused dan jika activity di-kill oleh Android, maka state game perlu disimpan dan
dikembalikan (bayangkan marahnya user jika state kembali ke awal). Demikian juga
untuk app yang menggunakan sensor, koneksi dengan sensor perlu dilepaskan saat app
di-pause atau distop untuk menghemat batere.
Active/Running

hilang fokus tapi masih visible

Paused

sistem kekurangan memori


tidak visible

Destroyed

sistem kekurangan memori?

Stopped

Saat activity di-pause, maka akan dipanggil onPause(). Ini artinya activity masih terlihat
walaupun cuma sebagian. Isi dari onPause tidak boleh terlalu berat, seperti menulis ke database
karena akan memperlambat proses transisi ke activity lain. Umumnya onPause digunakan untuk
tiga hal: menstop animasi atau aktivitas yang menggunakan banyak CPU; commit input dari user
(misalnya draft email); melepaskan system resources seperti sensor atau kamera.
Saat activity berubah dari pause menjadi stop, maka akan dipanggil onStop(). Pada method ini
dapat dilakukan komputasi yang kompleks untuk menyimpan state. Pada saat kondisi stop,
activity sama sekali tidak muncul di layar dan fokus sudah berada di app lain.
Jika app kembali aktif, maka akan dipanggil onResume(). Pada method ini lakukan proses untuk
mengembalikan kondisi app seperti semula (kebalikan dari onStop). Selain onResume, untuk
state stop ada event lain yang terlibat yaitu onRestart. Hubungan keduanya dapat dilihat pada
gambar bawah

versi April 2014

58

diambil dari: http://developer.android.com/training/basics/activity-lifecycle/stopping.html

Dari gambar diatas, dapat dilihat urutan pada dari state stop menuju resumed urutannya
adalah OnRestart() onStart() onResume()
Contoh penggunaan onPause() dan onResume() dapat dilihat pada subbab mengenai
sensor.

Simpan dan Load Activity State


Coba lihat project yang pernah anda buat sebelumnya, dalam setiap project, di method
onCreate dapat dilihat parameter bertipe Bundle.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

savedInstanceState adalah objek yang menyimpan state activity seperti isi widget
sehingga saat app masuk ke pause/stop dan kemudian kembali, widget terisi kembali
secara otomatis.
Kita dapat memanfaatkan Bundle ini untuk menyimpan variabel-variabel yang perlu
dikembalikan state-nya pada saat activity aktif dari kondisi stop atau destroyed.
Contoh berikut akan lebih menjelaskan masalah ini. Pertama buatlah app dengan dua
button dan satu textview. Saat button simpan diklik maka variabel nama dan skor akan
terisi. Sedangkan saat tombol tampil diklik maka isi variabel akan dicetak di TextView.

versi April 2014

59

Layoutnya adalah sebagai berikut:


<Button
.
android:onClick="klikButtonTampil"
android:text="Tampil" />
<Button

android:onClick="klikButtonSimpan"
android:text="Simpan" />

Implementasi dua button di MainActivity adalah sebagai berikut.


String nama;
int skor;
public void klikButtonSimpan(View v) {
skor = 100;
nama = "budi martami";
}
public void klikButtonTampil(View v) {
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText("skor:"+skor+" nama: "+nama);
}

Coba jalankan program.

Klik simpan lalu klik tampil, maka hasilnya akan seperti ini:

versi April 2014

60

Sekarang coba rotate screen (ctrl-F11 di emulator). Proses rotate akan men-destroy
activity dan mengcreate ulang. Sekarang coba klik tampil (jangan klik simpan), efeknya
akan seperti ini:

Terlihat bahwa variabel yang dimiliki Activity akan hilang saat didestroy. Bayangkan
efeknya jika dengan merotate device semua variabel di activity hilang. Tentu saja
pengguna berasumsi proses rotate tidak akan merubah state dari activity. Ini juga berlaku
misalnya saat pengguna pindah ke activity lain dan kemudian kembali ke activity semula,
mereka akan berharap kondisi activity akan sama seperti sebelum ditinggalkan. Walaupun
pada kenyataanya Android dapat mendestroy activity yang ditinggalkan tersebut.
Untuk mengatasi ini, kita perlu meng-override dua method di MainActivity, pertama
onSaveInstanceState
untuk
menyimpan
variabel
dan
kedua
adalah
onRestoreInstanceState untuk mengembalikan state. Contoh kodenya adalah sebagai
berikut:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
//simpan variabel
//method ini dipanggil sebelum onStop
savedInstanceState.putInt("state_skor", skor);
savedInstanceState.putString("state_nama", nama);
//jangan lupa panggil superclass
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Restore nilai
skor = savedInstanceState.getInt("state_skor");
nama = savedInstanceState.getString("state_nama");
}

Jalankan dan perhatikan efeknya (simpan tampil rotate (ctrl-F11) tampil). Maka
variabel akan tetap tersimpan. Karena sebelum distop variabel disimpan di
savedInstanceState dan saat diaktifkan akan direstore.
Gambaran berikut memperlihatkan posisi dua method untuk menyimpan state:

versi April 2014

61

Diambil dari http://developer.android.com/training/basics/activity-lifecycle/recreating.html

versi April 2014

62

Fragments
Fragment adalah komponen user interface dari activity. Satu activity dapat mengadung
dan mengelola beberapa fragment. Fragment bermanfaat untuk membuat user interface
yang modular, dapat beradaptasi untuk layar lebar seperti tablet dan mudah di-reuse
(beberapa activity dapat menggunakan fragment yang sama).
Fragment terkait erat dengan activiy, jika activity dalam kondisi pause, maka semua
fragment yang dimiliki oleh activity juga akan berada dalam kondisi pause, demikian
juga dengan saat di-destroy. Tapi jika activity sedang berjalan fragment dapat diatur (bisa
di-add, bisa di-remove).
Fragment diperkenalkan mulai dari Android 3.0 (Honeycomb), tapi dengan adanya
support library, maka Android versi 1.6 ke atas dapat memanfaatkan fragment, walaupun
dengan cara yang sedikit berbeda. Contoh pada modul ini akan menggunakan support
library package.

Penambahan Fragment melalui XML


Sekarang kita akan mencoba membuat app yang memiliki satu activity dengan dua
fragment.
Pertama, cek apakah android-support-v4.jar sudah ada di libs.

Jika belum, install Android Support Library package di bagian Extras.

Buat project baru, pilih project properties. Lalu pilih tab library (gambar bawah)

versi April 2014

63

Pilih eksternal JAR, lalu pilih dibagian sdk/extras/android/support/v4: android-supportv4.jar


Selanjutnya buat class baru yang merupakan turunan dari Fragment, beri nama
FragmentSatu
public class FragmentSatu extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_satu, container, false);
}
}

Buat layout untuk fragment ini (New Other Android Android XML Layout
File), beri nama fragment_satu.xml, tambahkan satu LargeText dengan isi seperti ini:

Sekarang buat yang sama untuk fragment kedua, buat class baru, beri nama FragmentDua
public class FragmentDua extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_dua, container, false);
}
}

Lalu buat layout fragment_dua.xml

Sekarang kita sudah mempunyai dua fragment. Sekarang kita akan menambahkan
fragment di activity utama. Ada dua cara, pertama melalui layout XML dan kedua secara
dinamik. Kita akan coba cara yang pertama, yaitu melalui XML.

versi April 2014

64

Buka activity_main.xml lalu tambahkan code berikut, sesuaikan classpath (edu.upi.cs)


dengan classpath yang anda gunakan. Pastikan classpath dan nama fragment sesuai,
karena kalau tidak akan terjadi error saat runtime.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="edu.upi.cs.yudiwbs.cobafragment.FragmentSatu"
android:id="@+id/fragment_satu"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="edu.upi.cs.yudiwbs.cobafragment.FragmentDua"
android:id="@+id/fragment_dua"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>

Kemudian di MainActivity, ganti Activity menjadi FragmentActivity:


public class MainActivity extends FragmentActivity {

Penting: Lupa mengganti Activity menjadi FragmentActivity akan menyebabkan Error


inflating class fragment

Hasilnya jika dicoba pada tablet akan seperti ini, dua fragment akan muncul bersamaan:

Terlihat dengan model fragment, user interface akan lebih modular dan lebih mudah
untuk di-reuse.

Penambahan Fragment secara Dinamis


Pada materi sebelumnya, kita menambahkan dua fragment dalam satu activity melalui
layout XML. Kelemahan penggabungan dengan XML adalah fragment tidak dapat di
add/delete/replace secara dinamik.

versi April 2014

65

Berikutnya kita akan menambah dan merubah fragment secara dinamik. Buat project
baru. Copy file class dan layout XML untuk fragmentSatu dan fragmentDua dari project
sebelumnya (lewat package explorer).

Selanjutnya modifikasi activity_main.xml seperti gambar berikut (rincian XML ada


dibawah gambar). Ada dua button dan satu framelayout. Saat button Fragment1
ditekan maka frameLayout akan diisi oleh fragment pertama dan demikian juga dengan
button Fragment2.

XML activity_main adalah sebagai berikut:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickBtnFrame1"
android:text="Fragment1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/button1"
android:onClick="clickBtnFrame2"
android:text="Fragment2" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button1" >
</FrameLayout>
</RelativeLayout>

Untuk menambah dan menghapus fragment secara dinamik, gunakan


FragmentTransaction. Sedangkan untuk menyimpan history frame agar saat user

versi April 2014

66

menekan back kembali ke fragment sebelumnya, gunakanlah method addToBackStack.


Berikut adalah code lengkap untuk class MainActivity:
import
import
import
import
import

android.os.Bundle;
android.support.v4.app.FragmentActivity;
android.support.v4.app.FragmentTransaction;
android.view.Menu;
android.view.View;

public class MainActivity extends FragmentActivity {


int fragmentAktif;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//jika setelah restore, tidak perlu
//dibuat lagi fragmentnya karena sudah ada
//kalau dibuat hasilnya nanti dua fragment yang bertumpuk
if (savedInstanceState != null) {
}

return;

//buat fragment1
FragmentSatu fSatu = new FragmentSatu();
//ambil fragment transaction, isi fragment_container dengan fragment pertama
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, fSatu).commit();
fragmentAktif = 1;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void clickBtnFrame2(View v) {
if (fragmentAktif==2) {
//fragment dua sudah aktif, tidak perlu melakukan apa2
return;
}
//ganti isi frame_container dengan frame 2
FragmentDua fDua = new FragmentDua();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// ganti isi container dengan fragment 2
// pindahkan fragment sebelumnya ke backstack
transaction.replace(R.id.fragment_container, fDua);
//dengan menambahkan ke backstack maka user dapat kembali
//ke fragment sebelumnya saat user menekan tombol back.
//state dari fragment yang diganti & masuk ke backstack adalah "stopped"

versi April 2014

67

//tapi kalau tidak dimasukkan ke backstack, maka fragment yang


//diganti akan didestroy
transaction.addToBackStack(null);
// commit
transaction.commit();

fragmentAktif = 2;

public void clickBtnFrame1(View v) {


if (fragmentAktif==1) {
return;
}
FragmentSatu fSatu = new FragmentSatu();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fSatu);
transaction.addToBackStack(null);
transaction.commit();
fragmentAktif = 1;
}

Perlu diingat bahwa dengan menambahkan ke addToBackStack, fragment akan masuk ke


state stop. Tanpa addToBackStack, fragment akan di-destroy.

Komunikasi Activity Fragment


Satu activity dapat mengandung beberapa fragment, masalahnya bagaimana Activity
dapat berkomunikasi dengan fragment tersebut? atau bagaimana fragment bisa
berkomunikasi satu sama lain?
Untuk komunikasi dari activity ke fragment, dapat digunakan method
findFragmentById() untuk mendapatkan instance fragment. Setelah itu kita dapat
mengakses public method milik fragment tersebut. Sedangkan untuk mendapatkan
instance dari Activity dapat digunakan getActivity().
Kita akan modifikasi code pada contoh sebelumnya. Pada layout fragment_satu,
tambahkan satu textview di bagian atas, beri nama tvPesan (gambar dibawah)

Update FragmentSatu.java, tambahkan public method untuk menulis pesan di text view
di fragment ini, perhatikan penggunaan getView() untuk mendapatkan view fragment:
public void setPesan(String pesan) {
TextView tvPesan = (TextView) getView().findViewById(R.id.tvPesan);
tvPesan.setText(pesan);
}

versi April 2014

68

Kemudian pada layout activiy_main.xml, tambahkan satu button

Sekarang update MainActivity.java, tambahkan event button kirim pesan (perhatikan


penggunaan findFragmentById):
public void clickBtnKirimPesan(View v) {
if (fragmentAktif==1) {
//ambil fragment yang ada di container
FragmentSatu fs = (FragmentSatu) getSupportFragmentManager().
findFragmentById(R.id.fragment_container);
//panggil method di fragment tersebut
fs.setPesan("halo dari activity");
}

Jika dijalankan dan tombol Kirim Pesan diklik maka akan muncul pesan dari
MainActivity.

Komunikasi Fragment Activity


Untuk mendapatkan instance activity dapat digunakan getActivity(). Kita akan
memodifikasi contoh app sebelumnya dan membuat fragment dua mengirimkan data ke
main activity.
Pertama, ubah layout activity_main.xml, tambah satu label dan beri nama
tvPesanDrFragment

versi April 2014

69

Kemudian ubah class MainActivity, tambahkan method yang menulis pesan.


public void pesan(String s) {
TextView tvPesan = (TextView)findViewById(R.id.tvPesanDrFragment);
tvPesan.setText(s);
}

Sekarang ubah fragment_dua.xml sebagai berikut, tambahkan button, beri nama


bPesanKeActivity (gambar bawah)

Tambahkan kode berikut di class FragmentDua. Atribut android:onClick tidak dapat


digunakan, sehingga digunakan listener. Buat FragmentDua mengimplements
OnClickListener. Untuk mendapatkan activity, gunakan getActvity.
import
import
import
import
import
import
import

android.os.Bundle;
android.support.v4.app.Fragment;
android.view.LayoutInflater;
android.view.View;
android.view.View.OnClickListener;
android.view.ViewGroup;
android.widget.Button;

public class FragmentDua extends Fragment implements OnClickListener{


public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dua, container, false);
Button b = (Button) v.findViewById(R.id.bPesanKeActivity);
b.setOnClickListener(this);
return v;
}
@Override
public void onClick(View arg0) {
//solusi yang lebih ideal adalah menggunakan interface
//sehingga fragment tidak terikat dengan class MainActivity
MainActivity ma = (MainActivity) getActivity();
ma.pesan("Halo dari fragment dua");
}
}

Jalankan, pilih Fragment2, lalu klik Kirim ke Activity:

versi April 2014

70

Untuk komunikasi antara fragment dapat dilakukan melalui activity.

Dinamik Layout dengan Fragment


Fragment dapat berguna untuk membuat app yang memaksimalkan space lebih pada
tablet tetapi tetap optimal untuk device kecil. Gambar bawah memperlihatkan
penggunaan fragment untuk tablet dan smartphone.
Pada tablet, satu activity
mengandung layout dengan dua fragment A dan B, sedangkan pada smartphone ada dua
activity untuk masing-masing untuk fragment A dan fragment B. Model seperti ini
disebut dengan multi-pane UI.

diambil dari: http://developer.android.com/

TBD

ActionBar
Actionbar adalah bar yang berada diatas activity yang mulai diperkenalkan sejak Android
3. Action bar memperlihatkan identitas berupa judul dan icon activity, tempat fitur-fitur
utama (misalnya search, shared, create dsb), dan dapat digunakan untuk navigasi global.
Beberapa contoh action bar:

versi April 2014

71

(sumber: 8)

Untuk mengimplementasikan ActionBar pada Android dengan versi lebih kecil dari 3
dapat menggunakan library actionbarsherlock.com
Dalam aplikasi sebelumnya, sebenarnya kita secara default selalu membuat ActionBar
karena minimal SDK diset 11 (Android 3.0). Coba buka MainActvity.java dan lihat
function onCreateOptionMenu. Terlihat fungsi ini mengisi ActionBar dengan isi
res/menu/main.xml

Coba lihat /res/menu/main.xml

Kita akan bahas lebih detil tentang ini pada bagian berikutnya.

ActionItem
ActionItem berbentuk button atau text yang dapat diakses langsung dari ActionBar. Jika
tidak cukup, maka actionitem akan muncul di overflow menu.
Buat project baru, pastikan minimal SDK diisi dengan 11 (Android 3.0)

versi April 2014

72

Kemudian buka /res/menu/main.xml.


Isi dengan item sebagai berikut. Kita
menambahkan dua item Add dan Delete yang akan muncul jika tempatnya cukup
(ifRoom).

Saat dijalankan akan menghasilkan ActionBar sebagai berikut.

Sekarang kita akan buat aksi kalau ADD atau DELETE ditekan. Override fungsi
onOptionsItemSelected dan cek hasil getItemId().

String Resources
Pada kode diatas kata add dan delete dimasukkan ke dalam kode. Ini bukan praktek
yang baik (perhatikan warning pada /main.xml), karena akan menyulitkan jika app akan
diporting untuk bahasa lain. Solusinya adalah dengan menggunakan string resources.
Pertama-tama, buka /res/values/strings.xml. Perhatikan bahwa secara default telah ada
string untuk nama app (app_name) dan lainnya. Tambahkan add dan delete (gambar
bawah). Jangan lupa save setelah selesai.

versi April 2014

73

Selanjutnya resource dapat diakses dalam file xml dengan @string/nama_res"


sedangkan untuk mengaksesnya dalam source code gunakan R.string.nama_res.
Sekarang kita akan mengubah item menu. Buka /res/menu/main.xml ganti kata add
dan delete dengan @string/add dan @string/delete

Sedangkan untuk MainActivity.java, ganti dengan R.string.add dan R.string.delete.

Icon
Umumnya action bar menggunakan icon yang lebih mudah dikenali oleh pengguna.
Untuk menambahkan icon, cara yang paling mudah adalah mendownload Android design
icon di: http://developer.android.com/design/downloads/index.html
Setelah download dan ekstrak, pilih all_icons/holo_dark dan copy icon yang diinginkan
(dengan Windows Explorer) ke direktori /res/drawable-hdpi, /res/drawable-mdpi dan
/res/drawable-xhdpi. Ingat dalam pembahasan sebelumnya bahwa setiap resoulusi
membutuhkan gambar yang terpisah.
Setelah itu masuk ke package explorer dan refresh (F5), hasilnya akan seperti ini:

versi April 2014

74

Sesuai dengan penamaan standard untuk icon ActionBar, rename agar didahului dengan
ic_menu_ Untuk me-rename, klik kanan pada nama file refactor rename. Semua
resolusi secara otomatis akan diganti. Sehingga hasilnya sebagai berikut:

Sekarang buka res/menu/main.xml dan tambahkan atribut android:icon

Jalankan dan hasilnya akan seperti berikut:

versi April 2014

75

Jika kita ingin menambahkan teks disebelah icon, tambahkan nilai withText pada
android:showAsAction sebagai berikut:

Jika dijalankan hasilnya tidak berubah. Mengapa? karena tidak cukup ruang untuk
menambahkan teks. Coba ubah orientasi AVD menjadi landscape dengan ctrl-F11 maka
tulisan akan muncul (gambar bawah). Untuk mengembalikan menjadi portrait tekan ctrlF12.

Selain ifRoom dan withText, pilihan yang lain adalah never agar item hanya
muncul di overlflow menu (gambar bawah)

Sedangkan always akan memaksa item selalu muncul. Gunakan untuk item yang benarbenar sangat penting karena jika tidak mencukupi akan terjadi overlap.

Latihan:
Modifikasi latihan activity-intent pada halaman 40, tambahkan action item
delete dan edit saat detil data mahasiswa (layar2)

Action Bar untuk Froyo

versi April 2014

76

Navigation Drawer

versi April 2014

77

versi April 2014

78

Menyimpan Data
Android menyediakan beberapa cara untuk menyimpan data: file, relasional database
dengan SQLlite dan pasangan key/value yang disebut sistem preferences. Untuk sharing
antar aplikasi disediakan mekanisme yang disebut ContentProvider.

Shared Preferences
Shared Preferences (SP) adalah mekanisme untuk menyimpan pasangan key-value untuk
tipe data primitif (integer, double, string, booelan). SP cocok untuk penggunaan ringan
seperti menyimpan setting aplikasi dan kondisi user interface misalnya pada saat activity
masuk ke state sleep karena device menerima telepon.
Data dalam shared preferences disimpan dalam device android dalam bentuk XML.
Ada tiga mode untuk shared preferences (SP)
MODE_PRIVATE: hanya aplikasi yang membuat SP yang dapat mengakses data
MODE_WORLD_READABLE: aplikasi lain boleh membaca
MODE_WORLD_WRITEABLE: aplikasi lain boleh membaca sekaligus menulis.
Shared Preference objek untuk activity diperoleh melalui method getPreferences(). Kode
berikut memperlihatkan cara penggunaan SP. Jangan lupa memanggil commit!

Jalankan. Kemudian coba komentari bagian isi data, dan jalankan kembali aplikasi.

versi April 2014

79

Dapat dilihat data nama dan umur tersimpan walaupun aplikasi sudah ditutup.
Latihan:
Buat applikasi yang menyimpan berapa kali aplikasi telah dijalankan. Tampilkan
jumlah tersebut.

SQLite
SQLite adalah embedded database (hanya menggunakan sekitar 250KB memori) yang
menyediakan fasilitas relational DBMS termasuk SQL. Referensi lengkap SQLite dapat
dilihat di http://www.sqlite.org/ SQLite tidak hanya digunakan di Android.
Setiap aplikasi memiliki instance database tersendiri, dan berbeda dengan shared
preference, tidak disediakan fasilitas agar aplikasi dapat membaca database aplikasi lain.
Untuk menggunakan SQLite, sangat dianjurkan menggunakan class helper untuk
membuka dan menutup database, menginisiasi tabel dst. Helper juga digunakan saat
melakukan upgrade struktur database jika suatu saat aplikasi diupdate. Class helper ini
diturunkan dari class SQLiteOpenHelper.
Untuk latihan kita akan membuat aplikasi sederhana yang menyimpan data mahasiswa
berupa nama dan nomor telpon. Pertama kita buat class helper terlebih dulu. Buatlah
project Android, tambahkan ke dalam project tersebut satu class (ke project explorer,
pilih src/nama package; klik kanan New Class). Pastikan superclass kelas ini
adalah SQLiteOpenHelper. Beri nama class ini OpenHelper.

versi April 2014

80

Pada class OpenHelper berikut akan dibuat tabel Mahasiswa dan penanganan jika
database diuprade.

Selanjutnya kita akan membuat class yang melakukan manipulasi terhadap data (insert,
ambil data), beri nama DbMahasiswa Source code DbMahasiwa adalah sebagai berikut:
public class DbMahasiswa {
//class yang menampung record Mahasiswa
public static class Mahasiswa {
public String nama;
public String telepon;
}

versi April 2014

81

private SQLiteDatabase db;


private final Context con;
private final OpenHelper dbHelper;
public DbMahasiswa (Context c) {
con = c;
dbHelper = new OpenHelper(con,"",null,0);
}
public void open() {
db = dbHelper.getWritableDatabase();
}
public void close() {
db.close();
}
public long insertMahasiswa(String nama, String noTelp) {
ContentValues newValues = new ContentValues();
newValues.put("NAMA", nama);
newValues.put("TELEPON", noTelp);
return db.insert("MAHASISWA", null, newValues);
}
public Mahasiswa getMahasiswa(String nama) {
Cursor cur = null;
Mahasiswa M = new Mahasiswa();
//kolom yang diambil
String[] cols = new String [] {"ID", "NAMA", "TELEPON"};
//parameter, akan mengganti ? pada NAMA=?
String[] param = {nama};
cur = db.query("MAHASISWA",cols,"NAMA=?",param,null,null,null);
if (cur.getCount()>0) { //ada data? ambil
cur.moveToFirst();
M.nama = cur.getString(1);
M.telepon = cur.getString(2);
}
return M;
}
}

Setelah kita membuat class helper dan class dbMahasiswa, sekarang kita akan
memanfaatkan dua kelas tersebut. Kembali ke activity utama yaitu class MainActivity.
Tambahkan kode dibagian onCreate sebagai berikut:

versi April 2014

82

Selain tipe INTEGER dan TEXT yang digunakan pada contoh diatas, dapat digunakan
tipe REAL, BLOB. Semua tipe lain seperti boolean, date harus dimasukkan ke dalam
tipe tersebut. SQLite tidak melakukan pengecekan tipe, sehingga bisa saja memasukkan
tipe

Group By, Having, Order By


Pada kode sebelumnya dapat dilihat penggunaan db.query untuk mengambil data
mahasiswa dengan nama tertentu.

Method query menerima tujuh parameter. Parameter pertama adalah nama table,
parameter kedua adalah array kolom yang akan diambil (SELECT), parameter ketiga
adalah bagian seleksi record (bagian setelah where), parameter keempat adalah isi
bagian seleksi. Parameter 5, 6 dan 7 adalah bagian group by, having dan order by.
Contoh penggunaan parameter 5-7 adalah sebagai berikut: jika kita menambahkan field
KELAS pada tabel MAHASISWA dan kita ingin menampilkan jumlah mahasiswa per
kelas (contoh misalnya ada kelas A, B, C dst), tapi hanya kelas yang mempunyai anggota
>1 dengan kelas terurut descending, maka query-nya adalah sebagai berikut:
select kelas, count(*) as jum from mahasiswa
group by kelas
having jum > 1
order by kelas desc;

versi April 2014

83

Maka di dalam program pemanggilan quernya adalah sebagai berikut:

group by
having

order by

RawQuery
Selain method query, tersedia juga rawQuery untuk memasukkan langsung query.
Sebagai contoh, berikut perbandingan antara query dengan rawQuery

Mana yang lebih baik? beberapa sumber mengatakan query lebih cepat dan dan lebih
mudah untuk dibaca daripada rawQuery.

Loop Semua Record


Untuk mengambil data semua record,
seperti pada contoh berikut

dapat digunakan moveToNext()

dalam loop

alternatif lain yang dapat digunakan untuk loop semua record adalah adalah:

versi April 2014

84

Mengisi ListView dengan Record


Listview dapat langsung dihubungkan dengan database dan untuk mencegah user
interface yang tidak responsif (ANR: Application Not Responding), idealnya data diload
di background.
Untuk mencapai hal ini dapat digunakan SimpleCursorAdapter, ContentProvider dan
Loader. Sayangnya hal ini cukup kompleks (mudah-mudahan akan lebih disederhanakan
di API berikutnya). Berikut adalah contoh penggunakan ketiga class tersebut.
Pertama buat project baru:

Seperti dalam contoh sebelumnya, buat class helper yang merupakan turunan dari kelas
SQLiteOpenHelper.
Catatan: untuk dapat menggunakan cursor adapter, table harus mengandung field _id
(dan harus huruf kecil)
package edu.upi.cs.yudi.listviewdb;
import
import
import
import

android.content.Context;
android.database.sqlite.SQLiteDatabase;
android.database.sqlite.SQLiteOpenHelper;
android.database.sqlite.SQLiteDatabase.CursorFactory;

public class DbHelper extends SQLiteOpenHelper {


private static final int DATABASE_VERSION =1;
private static final String DATABASE_NAME ="dbMhs";

versi April 2014

85

//cursoradapter mewajibkan nama _id


//harus _id dengan huruf kecil, JANGAN _ID
private static final String TABLE_CREATE =
"CREATE TABLE MHS (_id integer primary key autoincrement, " +
"nama text);";

public DbHelper(Context context, String name,


CursorFactory factory, int version) {
super (context,DATABASE_NAME,factory,DATABASE_VERSION);
}
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//create database
db.execSQL(TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer) {
//jika database diupgrade, hapus yang lama, buat yang baru
db.execSQL("DROP TABLE IF EXISTS MHS");
onCreate(db);
}
}

Selanjutnya kita akan membuat class Contentprovider untuk mengakses tabel.

Catatan:
Biasanya Contentprovider dibuat agar data app kita dapat diakses oleh
app lain. Tapi class Contentprovider juga dapat digunakan di app sendiri
secara private (tidak bisa diakses app lain). Keuntungan content
provider adalah:
1. Dapat dieksekusi secara asynchronus, sehingga menghindari
error app not responding.
2. Memberikan akses tunggal terhadap data.
3. Memudahkan hubungan antara view (widget) dengan data
melalui ContentObserver milik ContentResolver.
4. Dapat dimanfaatkan untuk rest client app.
Kerugian menggunakan contentprovider? relatif rumit.

Class ini merupakan turunan dari ContentProvider (gambar bawah)


versi April 2014

86

Untuk tahap pertama hanya insert dan query yang dibuat. Update dan delete akan
dibahas berikutnya. Contentprovider yang dibuat ini juga dapat digunakan untuk widget
yang lain, tidak harus berupa ListView. Cara penggunaanya dapat dilihat di MainActivity
nanti.
package edu.upi.cs.yudi.listviewdb;
import
import
import
import
import
import
import

android.content.ContentProvider;
android.content.ContentResolver;
android.content.ContentValues;
android.content.UriMatcher;
android.database.Cursor;
android.database.sqlite.SQLiteDatabase;
android.net.Uri;

public class MhsContentProvider extends ContentProvider {


// database
private DbHelper database;
// konstanta2 dibawah mendefinisikan bagaimana contentprovider ini diakses
// contentprovider diakses melalui URI
// contoh penggunaa URI ini dapat dilihat di MainActivity

private static final int MHS = 1;


private static final int MHS_ID = 2;
private static final String AUTHORITY = "edu.upi.cs.yudi.listviewdb.contentprovider";
private static final String BASE_PATH = "mhs";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + BASE_PATH);
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, MHS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", MHS_ID);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//insert data
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
long id = 0;
switch (uriType) {
case MHS:
id = sqlDB.insert("MHS", null, values);
break;

versi April 2014

87

default:
throw new IllegalArgumentException("URI tdk dikenal: " + uri);
}
//notifikasi
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
@Override
public boolean onCreate() {
database = new DbHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs,String sortOrder) {
//query tabel
SQLiteDatabase db = database.getWritableDatabase();
Cursor cur=null;
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case MHS:
//ambil semua
cur = db.query("MHS",projection,selection,selectionArgs,sortOrder,null,null);
break;
case MHS_ID:
// ambil berdasarkan id nanti dibuat
break;
default:
throw new IllegalArgumentException("URI tidak dikenal: " + uri);
}
//notifikasi
cur.setNotificationUri(getContext().getContentResolver(), uri);
return cur;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
// nanti dibuat
return 0;
}

@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// nanti dibuat
return 0;
}
@Override
public String getType(Uri arg0) {
// nanti dibuat
return null;
}
}

Content provider ini harus didaftarkan di AndroidManifest. Buka dan tambahkan di


dalam <application>. android:exported=false menunjukkan bahwa content provider ini

versi April 2014

88

private dan tidak dapat diakses app lain. Sedangkan android:name adalah nama kelas,
penggunaan titik pada .MhsContentProvider merupakan singkatan dari nama
app.
Jadi
.MhsContentProvider
artinya
sama
dengan
edu.upi.cs.yudi.listviewdb.MhsContentProvider
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="edu.upi.cs.yudi.listviewdb.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:exported="false"
android:name=".MhsContentProvider"
android:authorities="edu.upi.cs.yudi.listviewdb.contentprovider" >
</provider>
</application>

Setelah Helper dan ContentProvider dibuat, selanjutnya kita akan mempersiapkan


ListView. Caranya
seperti
ListView
pada
contoh
sebelumnya.
Buka
layout/activity_main.xml, drag listview.

Selanjutnya buat xml layout baru sebagai isi dari baris di listview (pilih layout, klik
kanan new Android XML ) Beri nama row.xml, dan tambahkan dua textview. Ganti
namanya dengan tvNama dan tvId.

versi April 2014

89

Selanjutnya kita akan melengkapi ActivityMain.java. Activity ini mengimplemen


LoaderCallback sehingga data akan diload dibackground dan baru diisi ke ListView saat
sudah selesai. Pada activity ini akan diinsert dua record kemudian ditampilkan dalam
listview.
package edu.upi.cs.yudi.listviewdb;
import
import
import
import
import
import
import
import
import
import

android.os.Bundle;
android.app.Activity;
android.view.Menu;
android.widget.ListView;
android.widget.SimpleCursorAdapter;
android.content.ContentValues;
android.content.CursorLoader;
android.content.Loader;
android.database.Cursor;
android.app.LoaderManager;

//implementes LoaderManager
public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
//adapter untuk listview
private SimpleCursorAdapter adapter;
private void insertData() {
//masukkan dua data untuk testing
ContentValues values = new ContentValues();
values.put("nama", "rudi");
//perhatikan penggunaan URI untuk mengidentifikasi contentprovider
//isi dari MhsContentProvider.CONTENT_URI adalah:
// content://edu.upi.cs.yudi.listviewdb.contentprovider/mhs
getContentResolver().insert(MhsContentProvider.CONTENT_URI, values);

values = new ContentValues();


values.put("nama", "budi");
getContentResolver().insert(MhsContentProvider.CONTENT_URI, values);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView lv = (ListView) findViewById(R.id.listView1);
//testing insert data. Setelah dijalankan sekali, bisa dikomentari
insertData();
//harus _id dengan huruf kecil!
String[] proj = new String[] { "_id","nama"};
// widget UI yang dipetakan sesuai field diatas (di row.xml)
int[] to = new int[] { R.id.tvId, R.id.tvNama };
getLoaderManager().initLoader(0, null, this);
//adapter yang digunakan adalah simplecursoradapter
adapter = new SimpleCursorAdapter(this, R.layout.row, null, proj,to, 0);

versi April 2014

90

lv.setAdapter(adapter);

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//load data ke cursor
//harus ada _id dengan huruf kecil!
String[] projection = { "_id", "nama" };
CursorLoader cursorLoader = new CursorLoader(this,
MhsContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cur) {
//dipanggil saat cursor sudah terisi, dilakukan
//dibackground sehingga user interface tetap responsif
//isi adapter dengan cursor yang sudah terisi
adapter.swapCursor(cur);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
//reset, kosongkan
adapter.swapCursor(null);
}

versi April 2014

91

Latihan SQLite1:
Buat applikasi untuk menyimpan datamahasiswa (NIM, NAMA, ALAMAT). Buatlah
menu untuk menambahkan data dan mencari berdasarkan NIM (NIM diinput oleh user).

Latihan SQLite2:
Modifikasi latihan activity-intent agar dapat menyimpan ke database.

File
[todo: cek untuk Android versi >=3.0?]
File dapat disimpan baik di dalam device maupun di media penyimpanan (SD card).
Secara default, aplikasi tidak dapat mengakses file milik aplikasi lain. Bagi anda yang
telah mengenal stream dan file di Java, anda dapat membaca secara cepat bagian ini,
karena tidak ada perbedaan antara Java dan Android. Class yang mensupport operasi file
disediakan di package java.io.*

Stream
Pemrosesan file dalam jumlah besar, yang membutuhkan kinerja yang tinggi masih
dibutuhkan berbagai bidang. Misalnya aplikasi backend yang mengelola dokumen di
perusahaan, aplikasi pengolahan teks, aplikasi pemroses XML, HTML, aplikasi
simulasi-simulasi dan sebagainya. Penguasaan stream dan file akan membantu anda
untuk memecahkan berbagai masalah
Stream adalah aliran data. Bayangkan stream sebagai sungai yang mengalirkan air.
Seperti sungai, stream mengalirkan byte-byte data. Pemrosesan input dan output di Java
pada prinsipnya menggunakan konsep stream ini.

Gambar 1: Input Stream (diambil dari http://download.oracle.com/javase/tutorial)

versi April 2014

92

Gambar 1: Output Stream (diambil dari http://download.oracle.com/javase/tutorial)


Untuk membantu programmer, tersedia banyak class-class untuk memproses stream,
bahkan lebih dari 60 kelas! (lihat gambar 3 dan gambar 4). Tentu saja tidak semua kelas
tersebut harus digunakan, programmer bisa memilih kelas mana yang dibutuhkan untuk
menyelesaikan masalahnya.

Persiapan
Sebelum memulai, pastikan emulator sudah memiliki SD-Card (Start All Program
Android SDK Tools)

Lalu untuk setiap project yang akan mengakses ke SD Card, tambahkan ijin untuk
menulis ke media penyimpanan external di AndroidManifest.xml

versi April 2014

93

File Teks
Sebelum mulai, pastikan virtual device telah diset SD-Card dan AndroidManifest telah
ditambahkan ijin untuk menulis (baca bagian persiapan)
File teks penting untuk menulis data, XML, HTML dan sebagainya. File teks dianggap
sebagai stream dari karakter. Untuk menulis ke file teks, cara yang paling mudah adalah
dengan menggunakan class PrintWriter. Berikut adalah contoh program yang menulis dua
baris ke file teks.

Sedangkan untuk membaca, dapat digunakan class Scanner yang dapat membaca baris
demi baris. Berikut contoh codenya, letakkan di bawah code atas.

versi April 2014

94

Latihan: buat file teks berisi


<html>
<body> Halo </body>
</html>

Objek Stream
Java telah menyediakan fasilitas agar objek dapat disimpan ke dalam stream secara
otomatis dengan mudah. Class yang digunakan adalah ObjectOutputStream dan
ObjectInputStream.
Setelah membuat project baru (pastikan AndroidManifest.xml-nya telah ditambahkan ijin
menulis ke external!) Sekarang coba kita buat class Mahasiswa sebagai berikut.
Tambah class baru (Filenewclass). Perhatikan penggunaan interface
java.io.Serializable yang menandakan bahwa class ini dalam disimpan ke dalam stream

versi April 2014

95

Codenya sebagai berikut. Perhatikan variabel serialVersionUID untuk menyatakan versi


class. Jangan lupa class Mahasiswa ini mengimplementas interface Serializable.

Selanjutnya, buat program untuk menulis dua objek mahasiswa ke dalam class. Penulisan
objek ke stream sangat mudah, hanya dengan class ObjectOutputStream dan method
writeObject. Buatlah code ini di activity Main.

versi April 2014

96

Catatan:
Perhatikan penggunaan code
ObjectOutputStream out =
new ObjectOutputStream (new FileOutputStream(namaFileOutput));
Pada code diatas Objek FileOuputStream dibungkus dengan ObjekOutputStream. Ini yang disebut dengan stream layering,
pbin = new PushbackInputStream(
new BufferedInputStream(new FileInputStream("pegawai.dat"))));

Walaupun pada awalnya teknik layering stream ini terlihat sulit, tapi teknik ini sangat bermanfaat untuk mengkombinasikan be

Sekarang kita lanjutkan ke pembacaan objek yang telah dituliskan. Untuk membaca file
berisi objek digunakan class FileInputStream dan ObjectInputStream;

versi April 2014

97

Latihan:
Buatlah class User dengan atribut username dan password. Simpan data objek user (minimal 3 user) ke dalam Android menggunakan file teks dan file obje

versi April 2014

98

Sensor
Android mendukung berbagai sensor, mulai dari yang umum tersedia seperti
accelerometer, magnetometer, GPS sampai barometer, termometer dan pengukur
kelembaban.

Accelerometer
Accelerometer adalah alat yang mengukur akselerasi atau percepatan (perubahan
kecepatan) baik yang disebabkan hal yang statik seperti gaya gravitasi (ingat bahwa
benda yang jatuh mengalami percepatan) maupun perubahan dinamik seperti saat device
bergerak atau bergetar.
Dengan mengukur gaya gravitasi, kita bisa mengetahui sudut kemiringan device.
Sedangkan dengan mengukur akselerasi dinamik kita bisa mengetahui ke arah mana
benda bergerak dan secepat apa.
Penggunaan accelerometer di smartphone/tablet yang paling umum adalah mendeteksi
posisi portrait dan landscape. Selain itu telah ada app yang memanfaatkan accelerometer
untuk menghitung kecepatan dan jarak lari, membunyikan alarm jika device dipindahkan,
game dan sebagainya.
Sebagian besar device Android memiliki sensor accelerometer ini. Sensor ini mengukur
perubahan kecepatan di tiga sumbu: x, y dan z (gambar bawah). Satuannya adalah
m/det^2. Gaya gravitasi selalu mempengaruhi. Sehingga jika device diletakkan diam,
nilai sumbu z tetap terbaca sekitar 9.8m/det^2.

Diambil dari: http://developer.android.com/reference/android/hardware/SensorEvent.html

Untuk menggunakan sensor di Android, class yang harus digunakan adalah


SensorManager untuk mengetahui apakah device mensupport sensor yang kita inginkan.
Kemudian class Sensor untuk mendapatkan data dari sensor dan interface
SensorEventListener yang diimplement oleh activity.

versi April 2014

99

Buat project baru, tambahkan kode berikut di MainActivity.


import
import
import
import
import
import
import
import
import
import

android.hardware.Sensor;
android.hardware.SensorEvent;
android.hardware.SensorEventListener;
android.hardware.SensorManager;
android.os.Bundle;
android.app.Activity;
android.content.Context;
android.util.Log;
android.view.Menu;
android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {


private SensorManager mSensorManager;
private Sensor mSensor;
private TextView tvHasil;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvHasil = (TextView) findViewById(R.id.textView1);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
//device memiliki accelerometer,lanjutkan
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);

}
else {
//tidak punya sensor accelerometer, tampilkan pesan error
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// kalau akurasi berubah
}
@Override
public void onSensorChanged(SensorEvent event) {
double ax=0,ay=0,az=0;
// menangkap perubahan nilai sensor

//if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER) {
ax=event.values[0];
ay=event.values[1];
az=event.values[2];
//ax,ay,az bisa digunakan
tvHasil.setText("x:"+ax+" y:"+ay+" z:"+az);

}
@Override
protected void onPause() {
//app kehilangan fokus (misal user menerima telp), lepaskan sensor
super.onPause();
mSensorManager.unregisterListener(this);
}

versi April 2014

100

@Override
protected void onResume() {
//app kembali
super.onResume();

mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);


//SENSOR_DELAY_NORMAL:sampling setiap 200,000 microseconds
//SENSOR_DELAY_GAME: 20,000 microsecond
//SENSOR_DELAY_UI: 60,000 microsecond
//SENSOR_DELAY_FASTEST: 0 microsecond

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

Masalahnya adalah AVD tidak mensupport accelerometer sehingga saat app harus
dijalankan pada device langsung. Caranya bisa dengan langsung menghubungkan atau
manual melalui APK.
Agar langsung dapat menjalankan app pada device, hubungan handphone/tablet dengan
komputer melalui kabel USB. Pastikan USB driver telah terinstall. Untuk jenis Nexus,
usb driver dapat diinstall melalui SDK manager (Extra Google USB Driver).
Kemudian klik kanan project Run As Run Configuration

Pilih tab target, lalu pilih launch on all dengan Active Devices

versi April 2014

101

Kemudian pada device, jalankan USB Debugging dengan pilihan Setting Developer
Options USB Debugging.

Catatan: Jika menu Developer Option tidak muncul pada Android versi 4.2.*, maka
untuk mengaktifkannya pilih settings About Phone, lalu tap Build Number
sebanyak tujuh kali.

Orientasi: Yaw (Azimuth), Pitch & Roll


Dengan mengkombinasikan sensor accelerometer dan magnetometer maka dapat
diperoleh pitch, roll dan yaw. Khusus untuk yaw, posisi yang didapat sesuai dengan
medan magnet bumi sehingga dapat digunakan sebagai kompas. Ini sebabnya posisi yaw
sering disebut disebut azimuth.
Gambar berikut memperlihatkan dengan jelas apa yang disebut yaw, pitch dan roll.

Ketiga informasi ini (azimuth, roll, pitch) dapat dimanfaaatkan untuk banyak hal.
Azimuth dapat digunakan untuk kompas dan dikombinasikan dengan GPS bermanfaat
untuk augmented reality. Dengan GPS kita bisa mengetahui posisi device, tapi kita tidak
mengetahui ke arah mana device menghadap. Tetapi jika GPS dikombinasikan dengan
informasi azimuth dan pitch maka dapat diketahui ke arah mana device menghadap. Roll
dan pitch juga dapat digunakan untuk mengontrol game.

versi April 2014

102

Contoh Augmented Reality


(foto: nilsmengedoht http://www.flickr.com/photos/nilsmengedoht/5109833017/)

Berikut adalah contoh kode untuk mendapatkan tiga orientasi tersebut, penjelasan ada di
dalam kode. Pertama, tambahkan tiga Large textview pada layout, beri nama tvAzimuth,
tvPitch dan tvRoll.

import
import
import
import
import
import
import
import
import

android.hardware.Sensor;
android.hardware.SensorEvent;
android.hardware.SensorEventListener;
android.hardware.SensorManager;
android.os.Bundle;
android.app.Activity;
android.content.Context;
android.view.Menu;
android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {


private
private
private
private

SensorManager mSensorManager;
Sensor accel;
Sensor magneto;
TextView tvAzimuth,tvPitch,tvRoll;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

versi April 2014

103

mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);


if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
//device memiliki accelerometer,lanjutkan
accel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magneto = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
//register listener
mSensorManager.registerListener(this, accel,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magneto,
SensorManager.SENSOR_DELAY_NORMAL);
tvAzimuth = (TextView) findViewById(R.id.tvAzimuth);
tvPitch = (TextView) findViewById(R.id.tvPitch);
tvRoll = (TextView) findViewById(R.id.tvRoll);
}
else {
//tidak punya sensor , tampilkan pesan error
}
}
float[] mGravity;
float[] mGeomagnetic;
float azimuth;
float pitch;
float roll;
public void onSensorChanged(SensorEvent event) {
//menggunakan clone, agar persis sama
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values.clone();;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values.clone();;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
//ambil rotationmatrix
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
// orientation akan terisi: azimut, pitch and roll
// orieantation[0]:azimuth; orieantation[1]:pitch orieantation[2]:roll
// azimuth adalah arah utara-selatan-timur-barat
//dengan Math.toDegreee hasilnya -180 sd 180
azimuth = (float)Math.toDegrees((double)orientation[0]);
//dikonversi jadi 0 sd 360
// 0=Utara, 90=Timur, 180=Selatan, 270=Barat
azimuth = (azimuth + 360) % 360;
//print dua angka belakang koma, agar mudah dibaca
tvAzimuth.setText("Azimuth="+String.format("%6.2f",azimuth));
//pitch adalah rotasi kedepan & belakang
//bayangkan pesawat yg sedang dogfight dikejar musuh
//kemudian naik berputar sehingga berada di belakang musuhnya
pitch = (float) Math.toDegrees((double)orientation[1]);

versi April 2014

104

pitch = (pitch + 360) % 360;


tvPitch.setText("Pitch="+String.format("%6.2f",pitch));
//roll adalah rotasi ke kiri dan kekanan
//bayangkan pesawat yg sedang berbelok kekiri dan ke kanan
roll = (float) Math.toDegrees((double)orientation[2]);
roll = (roll+ 360) % 360;
tvRoll.setText("roll="+String.format("%6.2f",roll));
}
}
}
@Override
protected void onPause() {
//app kehilangan fokus (misal user menerima telp),
//lepaskan listener sensor
super.onPause();
mSensorManager.unregisterListener(this);
}
@Override
protected void onResume() {
//app kembali, daftarkan lagi listener
super.onResume();
mSensorManager.registerListener(this, accel,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magneto,
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
}

Jalankan di device dan coba lakukan gerakan pitch, roll dan yaw dan perhatikan angka
yang didapat.
Catatan: Penjelasan rinci tentang rotationmatrix dapat diperoleh di:
http://gentlenav.googlecode.com/files/DCMDraft2.pdf

Lokasi
Dengan GPS (Global Positioning Service), suatu device dapat diketahui posisi
geolokasinya. GPS menggunakan 24 satelit yang memancarkan sinyal secara bersamaan.
Sinyal berisi waktu kirim dan posisi satelit. Device akan menerima sinyal satelit itu
secara pasif (tidak memancarkan sinyal, hanya menerima). Berdasarkan kecepatan sinyal
sampai ke device maka dapat ditentukan jarak antara device dengan satelit. Minimal
diperlukan empat satelit berbeda untuk menentukan lokasi. Selain GPS, Rusia
mengembangkan sistem serupa yang disebut GLONASS dan Eropa mengembangkan
Galileo.

versi April 2014

105

Hampir semua device Android mendukung GPS dan sebagian mendukung kombinasi
GPS + GLONASS. Selain itu Android mendukung penentuan lokasi berbasis network
yang memanfaatkan cell tower dan wifi. GPS lebih akurat dibandingkan network location
provider, tetapi membutuhkan waktu lebih lama, akses ke langit dan lebih boros batere.
Ada dua cara untuk mendapatkan lokasi, pertama dengan Android Location API dan
Google Location API yang akan dibahas dalam subbab berikut:

Android Location API


Android menyediakan location API yang mengatur provider lokasi (GPS, network atau
pasif). Kita akan mencoba membuat aplikasi sederhana yang memanfaatkan lokasi.
Untuk lebih memahami proses pengambilan lokasi, jalankan app langsung pada device
(lihat subbab accelerometer untuk caranya).
Buat project baru. Edit AndroidManifest.xml karena app membutuhkan ijin dari user
untuk mengakses lokasi. Gunakan ACCESS_COARSE_LOCATION untuk lokasi
berdasarkan network dan ACCESS_FINE_LOCATION untuk lokasi berdasarkan GPS.
Jika kita menggunakan FINE_LOCATION maka tidak perlu lagi meminta
COARSE_LOCATION karena otomatis sudah termasuk.

Untuk mengambil lokasi, kita akan buat activity yang meng-implement LocationListener
dan kemudian dipassing ke LocationManager.

Pertama tambahkan tiga textview dalam activity_main.xml. Ganti id dengan tvStatus,


tvLat dan tvLng (gambar bawah).

versi April 2014

106

Berikut adalah code lengkap untuk class MainActivity, perhatikan comment yang ada.
Jalankan langsung di-device.
import
import
import
import
import
import
import
import
import
import

android.location.Criteria;
android.location.Location;
android.location.LocationListener;
android.location.LocationManager;
android.os.Bundle;
android.app.Activity;
android.content.Context;
android.text.format.Time;
android.view.Menu;
android.widget.TextView;

public class MainActivity extends Activity implements LocationListener {

TextView tvLat;
TextView tvLng;
TextView tvStatus;
double lat;
double lng;
long minTime;
float minDistance;
String locProvider;
LocationManager locMgr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvStatus = (TextView) findViewById(R.id.tvStatus);
tvLat = (TextView) findViewById(R.id.tvLat);
tvLng = (TextView) findViewById(R.id.tvLng);
// ambil location manager
locMgr = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

//ambil lokasi terakhir berdasarkan network agar cepat


//user dapat kesal jika diawal menunggu terlalu lama app mendapatkan lokasi
tvStatus.setText("ambil lokasi terakhir berdasarkan network");
locProvider = LocationManager.NETWORK_PROVIDER;
Location lastKnownLocation = locMgr.getLastKnownLocation(locProvider);
lat = lastKnownLocation.getLatitude();
lng = lastKnownLocation.getLongitude();
tvLat.setText(String.valueOf(lat));
tvLng.setText(String.valueOf(lng));
//sambil user melakukan aktivitas2 (misalnya)
//maka ambil lokasi yang lebih akurat dan terus mendengarkan
//perubahan lokasi device
//selanjutnya plih provider yang tinggi akurasinya
//dengan mengeset Criteria, tapi ingat semakin tinggi
//akurasi maka semakin boros menggunakan batere

versi April 2014

107

Criteria cr = new Criteria();


cr.setAccuracy(Criteria.ACCURACY_FINE);
//contoh penggunaan criteria yang lain:
//akurasi relatif rendah, tapi paling hemat batere
//cr.setAccuracy(Criteria.ACCURACY_COARSE);
//cr.setPowerRequirement(Criteria.POWER_LOW);

//berdasarkan kriteria, sistem akan memberikan


//provider yang paling tepat
locProvider = locMgr.getBestProvider(cr, false);

//1 menit: waktu refresh lokasi dalam milidetik (1*60*1000)


//pilih selama mungkin untuk menghemat batere tapi
//user masih bisa menerima
//long minTime = 1 * 60 * 1000;
minTime = 5 * 1000; //lima detik

//posisi pergeseran dalam meter


//lokasi akan diupdate jika telah melewati batas distance
minDistance = 1;
//onResume akan dipanggil dan mulai mendengarkan pergantian lokasi
}
@Override
protected void onResume() {
//mulai mendengarkan dari awal dan juga saat dibangunkan dari pause
super.onResume();
locMgr.requestLocationUpdates(locProvider, minTime, minDistance, this);
}
@Override
protected void onPause() {
//lepaskan listener, agar tidak memakan resources saat dipause
super.onPause();
locMgr.removeUpdates(this);
}
@Override
public void onLocationChanged(Location loc) {
//dipanggil saat lokasi berubah atau waktu refersh
lat = loc.getLatitude();
lng = loc.getLongitude();
tvLat.setText(String.valueOf(lat));
tvLng.setText(String.valueOf(lng));
Time now = new Time();
now.setToNow();

versi April 2014

108

tvStatus.setText("Direfresh berdasarkan: "+locProvider


+" Waktu: "+now.hour+":"+now.minute+":"+now.second);
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

Jika dijalankan maka pada saat awal lokasi akan diisi dengan cepat berdasarkan data
terakhir (network). Perhatikan icon GPS di kiri atas yang menyatakan GPS mulai
diaktifkan.

Setelah beberapa saat (bawa device ke dekat jendela atau ruang terbuka atau lapangan).
Maka akan muncul lokasi berdasarkan GPS yang diupdate setiap 5 detik. Jika anda
berada di dalam ruangan tertutup, maka layar dibawah tidak akan pernah muncul karena
lokasi GPS tidak pernah didapatkan:

Untuk menghemat batere, dapat dilakukan caching lokasi


(http://developer.android.com/guide/topics/location/strategies.html).
Tip: Untuk mendapatkan lokasi berdasarkan GSM, pastikan uncheck Settings ->
Applications Development Allow mock locations
versi April 2014

109

Latihan:
Buatlah app yang menyimpan data lokasi latitude, longitude, dan data
accelerometer (x,y,z) untuk suatu perjalanan dengan kendaraan (motor/mobil).
Simpan data tersebut beserta waktu pengambilan data ke dalam database.

Google Location API


Dibandingkan Android Location API, kelebihan Google Location API adalah lebih hemat
energi dan lokasi dapat diperoleh langsung karena proses mendapatkan lokasi dilakukan
melalui Google Play Service yang berjalan di background. Berbagai app yang
membutuhkan lokasi juga dapat menggunakan service secara bersama-sama sehingga
secara keseluruhan akan menghemat batere. Kelemahan utamanya, app jadi bergantung
pada layanan Google.

Instalasi Google Play Service


Google Location API dapat dijalankan di Android versi 2.3 ke atas, tetapi jika
menggunakan AVD harus menggunakan minimal versi 4.2.2. Untuk memanfaatkan
Google location, pertama yang harus dinstall (jika belum) adalah Google Play Service.
Jalankan SDK Manager (jika lewat Eclipse: Window Android SDK Manager) lalu
install komponen tersebut (gambar bawah).

Setelah berhasil, lihat lokasi Android SDK di kiri atas

lalu copy library yang berada di android SDK tersebut:


<android-sdk>/extras/google/google_play_services/libproject/google-playservices_lib/

versi April 2014

110

ke lokasi bebas asalkan bukan di direktori workspace dan sdk. Sekarang impor library
tersebut di workspace Ecplise dengan menu File Import, Android Existing Android
Code into Workspace (gambar bawah)

Pilih direktori library yang sudah kita copy, setelah muncul dialog (gambar bawah),
check copy projects into workspace lalu tekan finish.

Google-play-service_lib akan masuk ke workspace dan muncul dibagian project explorer

Mengambil Lokasi Terakhir


Sekarang kita akan buat app untuk mengambil koordinat terakhir. Buat project baru,
tambahkan Google Play Service lib ini sebagai library. Pada project explorer, klik kanan
lalu pilih properperties. Pilih Android, lalu add (gambar bawah).

versi April 2014

111

Setelah add di-klik akan muncul seperti gambar bawah. Pilihlah google-play-service_lib

Lalu pada file AndroidManifest.xml tambahkan elemen berikut di dalam elemen


<application>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />

Jangan lupa tambahkan permission ditambahkan di dalam elemen <manifest>


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Selanjutnya buat activity yang mengimplement ConnectionCallbacks untuk dua method:


onConnected yang dipanggil setelah terhubung dengan googleplay service dan
onDisconnected saat terputus.
Selain itu activity juga perlu mengimpelement OnConnectionFailedListener yang
menangani jika hubungan dengan googleplay service gagal dilakukan. Berikut kode
lengkapnya, penanganan kesalahan jika terjadi kegagalan hubungan dengan Google Play
Service belum ditangani (nanti akan dibahas kemudian).

versi April 2014

112

package edu.upi.cs.yudiwbs.cobagooglelocation;
import
import
import
import

android.location.Location;
android.os.Bundle;
android.support.v4.app.FragmentActivity;
android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
//implements ConnectionCallBacks dan OnConnectionFailedListener
public class CobaGoogleLocation extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
//client untuk mendapatkan lokasi
LocationClient mLocationClient;
//lokasi terakhir
Location mCurrentLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coba_google_location);
mLocationClient = new LocationClient(this, this, this);
}
/*
* Dipanggil saat Activity visible.
*/
@Override
protected void onStart() {
super.onStart();
// Connect the client.
mLocationClient.connect();
}
/*
* dipanggil saat activity tidak terlihat
*/
@Override
protected void onStop() {
// disconnect dengan client
mLocationClient.disconnect();
super.onStop();
}

@Override
public void onConnected(Bundle arg0) {
//method ini dipanggil saat sudah terhubung dgn client
Toast.makeText(this, "Terhubung", Toast.LENGTH_SHORT).show();
//akses terhadap lokasi
//hanya boleh dipanggil saat sudah connected
mCurrentLocation = mLocationClient.getLastLocation();
Toast.makeText(this, "Lat: "+mCurrentLocation.getLatitude()+
" Long:"+mCurrentLocation.getLongitude(),
Toast.LENGTH_LONG).show();
}

versi April 2014

113

@Override
public void onDisconnected() {
// dipanggil saat sudah tidak terhubung
Toast.makeText(this, "Disconnected", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
// sekarang tampilkan pesan dulu
// nanti ada mekanisme resolve
Toast.makeText(this, "Koneksi gagal.",
Toast.LENGTH_SHORT).show();
}
}

Mengambil Lokasi Secara Rutin


Selanjutnya kita akan membuat project yang menangkap lokasi secara reguler. Buat
project baru, tambahkan tiga label sebagai berikut, dengan id tvStatus, tvLat dan tvLang.

Untuk mengambil koordinat secara rutin, diperlukan tiga parameter:


1. update interval, menyatakan selang interval yang diinginkan, satuannya milidetik.
Jika diset 5000 (5 detik), maka app akan diberi update lokasi device setiap 5 detik
sekali. Tapi jika ada beberapa app yang menggunakan google location service,
maka interval sesungguhnya dapat lebih pendek lagi, karena untuk efisiensi, jika
app lain mendapat update lokasi, app kita akan mendapatkannya juga. Ini dapat
membuat app terlalu banyak mendapatkan update (overflow).
2. Untuk mencegah terjadinya overflow, dapat diset fastest interval untuk
menyatakan interval tercepat yang dimungkinkan. Misalnya jika diset 1000 (1
detik), maka paling cepat app akan diupdate setiap 1 detik.
3. Prioritas. Terdapat beberapa pilihan. Mulai dari yang prioritas paling tinggi yang
paling banyak menghabiskan energi yaitu PRIORITY_HIGH_ACCURACY
sampai dengan PRIORITY_NO_POWER yang paling hemat energi. Untuk
PRIORITY_NO_POWER, app tidak akan mendapatkan lokasi kecuali jika ada
app lain yang meminta lokasi.
Parameter tersebut kemudian dimasukkan pada objek LocationRequest yang kemudian
dipassing ke method LocationClient.requestLocationUpdates. Setelah method tersebut

versi April 2014

114

dipanggil, maka setiap kali update maka method onLocationChanged akan dipanggil
(callback).
Selain harus mengimplementasikan ConnectionCallbacks, OnConnectionFailedListener,
Activity
juga
harus
mengimplementasikan
LocationListener
(tapi
dari
com.google.android.gms.location bukan android.location). Berikut kode lengkapnya:
package edu.upi.cs.yudiwbs.cobagooglelocation;
import
import
import
import
import
import

android.location.Location;
android.os.Bundle;
android.support.v4.app.FragmentActivity;
android.text.format.Time;
android.widget.TextView;
android.widget.Toast;

import
import
import
import

com.google.android.gms.common.ConnectionResult;
com.google.android.gms.common.GooglePlayServicesClient;
com.google.android.gms.location.LocationClient;
com.google.android.gms.location.LocationRequest;

//implements ConnectionCallBacks dan OnConnectionFailedListener


//tambah LocationListener
//LocationListener sengaja dituliskan lengkap karena
//bisa tertukar dengan android.location.LocationListener
public class CobaGoogleLocation extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener {
//client untuk mendapatkan lokasi
LocationClient mLocationClient;
//lokasi terakhir
Location mCurrentLocation;
//untuk output
TextView tvLat;
TextView tvLng;
TextView tvStatus;
//parameter update lokasi
//interval update dalam Milidetik yang diinginkan
//jika tidak ada app lain yg mengakses, interval akan sesuai ini
//tapi jika ada app lain yg mengakses, interval bisa lebih pendek
private static final long UPDATE_INTERVAL = 1000 * 5; //5 detik
//interval tercepat yang dapat dihandle oleh app
//karena interval bisa lebih pendek daripada nilai UPDATE_INTERVAL
//sehingga dapat terjadi overflow, yaitu data update lebih cepat
//daripada yang app bisa handle
//untuk mengatasi itu dapat diset fasteset_interval sebagai batas
//tercepat
//jika diset 1 detik, maka *paling cepat* app akan diupdate lokasinya

versi April 2014

115

//tiap 1 detik
private static final long FASTEST_INTERVAL =1000 * 1; //1 detik
// objek berisi parameter2 update lokasi
LocationRequest mLocationRequest;
private Time waktu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coba_google_location);
mLocationClient = new LocationClient(this, this, this);
//init user interface
tvStatus = (TextView) findViewById(R.id.tvStatus);
tvLat = (TextView) findViewById(R.id.tvLat);
tvLng = (TextView) findViewById(R.id.tvLng);
waktu = new Time();
//siapkan paramter request
mLocationRequest = LocationRequest.create();
// akurasi tertinggi
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval dan fastetst update interval
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
/*
* Dipanggil saat Activity visible.
*/
@Override
protected void onStart() {
super.onStart();
// Connect ke client
mLocationClient.connect();
}
/*
* dipanggil saat activity tidak terlihat
*/
@Override
protected void onStop() {
// disconnect dengan client
mLocationClient.disconnect();
super.onStop();
}
@Override
public void onConnected(Bundle arg0) {
//method ini dipanggil saat sudah terhubung dgn client
tvStatus.setText("Terhubung.. mulai mengupdate");
//mulai update request dengan parameter

versi April 2014

116

//yang ada pada mLocationRequest


//selanjutnya jika ada update lokasi maka
//method onLocationChanged akan dipanggil
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
@Override
public void onLocationChanged(Location loc) {
//dipanggil setiap ada perubahan lokasi
//freq pemangilan sesuai parameter
//interval dan fastestinterval
//catat waktu update
waktu.setToNow();
String strWaktu = "Direfresh:"+
waktu.hour+":"+waktu.minute+":"+waktu.second;
tvStatus.setText(strWaktu);
//tulis latitude dan longitude
tvLng.setText(Double.toString(loc.getLongitude()));
tvLat.setText(Double.toString(loc.getLatitude()));
}
@Override
public void onDisconnected() {
// dipanggil saat sudah tidak terhubung
Toast.makeText(this, "Disconnected", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
// sekarang tampilkan pesan dulu
// nanti ada mekanisme resolve
Toast.makeText(this, "Koneksi gagal.",
Toast.LENGTH_SHORT).show();
}
}

Penanganan Error
Pada dua contoh sebelumnya, belum ditangani jika terjadi kesalahan saat koneksi dengan
Google Play Service. Beberapa kemungkinan error yang dapat terjadi misalnya user
belum melakukan sign-in, google play belum diupdate, tanggal yang salah dan
sebagainya (ingat kelemahan Google Location API adalah API ini bergantung pada
Google Play Service). Beberapa kesalahan dapat diselesaikan dengan memanggil intent.
Kita akan memodifikasi code pada bagian sebelumnya untuk menangani kesalahan saat
app mencoba terhubung dengan service.
Tambahkan konstanta berikut
//kode result setelah intent dipanggil, akan digunakan di
//onActvityResult
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;

versi April 2014

117

Kemudian ubah isi method onConnectionFailed yang akan dipanggil jika terjadi gagal
koneksi. Jika ada kemungkinan untuk solusi (misalnya harus login ulang dengan account
Google), maka akan dipanggil intent melalui startResolutionForResult. Setelah selesai
pemanggilan intent, onActivityResult akan dipanggil.

versi April 2014

118

@Override
public void onConnectionFailed(ConnectionResult cr) {
tvStatus.setText("Koneksi gagal, coba resolusi");
if (cr.hasResolution()) {
try {
//memungkinkan resolusi (misal install google
//play versi terbaru, login dll).
//Jalankan intent
//nanti hasilnya ditangkap di onActivityResult
cr.startResolutionForResult(
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
//tidak ada resolusi, tampilkan error code
Toast.makeText(this, "Tidak bisa melakukan koneksi,
kode:"+cr.getErrorCode(), Toast.LENGTH_SHORT).show();
}
}

onActivityResult akan dipanggil saat intent selesai, dicek melalui requestCode dan jika
resultCode berisi RESULT_OK maka artinya resolusi berhasil dan berhasil terhubung
dengan Google Play Service.
@Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
switch (requestCode) {
//hasil kiriman dari startResolutionForResult
case CONNECTION_FAILURE_RESOLUTION_REQUEST :
if (resultCode==Activity.RESULT_OK) {
//resolusi sukses
tvStatus.setText("Resolusi sukses, terhubung");
} else {
tvStatus.setText("Gagal terhubung");
}
break;
}
}

versi April 2014

119

Koneksi dengan Server


Ada beberapa alasan diperlukan koneksi dengan server diantaranya:
1. Device memiliki beberapa keterbatasan (komputasi, space). Server dapat
digunakan untuk memproses data dan hasilnya saja yang akan digunakan di
device.
2. Sinkronisasi data. Pengguna dapat mengambil data terkini atau mengupload data
tambahan.
Sebelum memulai, pastikan emulator telah terhubung dengan internet, jalankan browser
dan coba buka salah satu website.

Jika tidak terhubung dengan internet, dapat digunakan server local seperti Apache atau
PhpMyAdmin.
PENTING: Tambahkan di AndroidManifest permission untuk koneksi internet.
Tanpa menambahkan ini, program anda tidak akan berjalan!

Letakkan permission ini di atas application (gambar bawah)

Buat project baru dan tulis code berikut:

versi April 2014

120

Tambahkan class GetDataTask yang merupakan turunan dari Asynctask sebagai berikut.
Ganti isi variabel url jika Anda menggunakan localhost:

versi April 2014

121

Google Map
todo: Cek ulang apa masih valid codenya
Google Map adalah fitur yang disediakan oleh Google, dan bukan standard Android.
Sebelum memulai, pastikan Google API sudah terinstall untuk platform target dan AVD
untuk Google API juga sudah ada. Jika belum, silahkan update terlebih dulu.
Catatan:
Baca ini http://stackoverflow.com/questions/7841494/cannot-find-google-apis-for-android-sdk jika Google
API tidak ditemukan di Android SDK.

Diperlukan key yang didapat dari Google untuk menggunakan fasilitas ini.
Baca terlebih dulu https://developers.google.com/maps/documentation/android/mapkey
Kita akan membuat mapkey sementara yang dapat digunakan selama pengembangan.
Pertama-tama cari lokasi keystore untuk debug.
Dalam Eclipse, pilih Window Preferences klik Android, klik Build. Catat nilai
default debug keystore.

Sebagai contoh, dari gambar diatas lokasi keystore adalah di


c:\Users\user\.android\debug.keystore
Kemudian cari posisi keytool di JDK Java. Biasanya terdapat di:
c:\Program Files\Java\jdk1.7.0\bin
Lalu gunakan Start cmd, jalankan keytool dengan sintaks sebagai berikut. Sesuaikan
lokasi debug.keystore dengan yang ada di komputer anda. Ingat, saat ditanya password
ketikkan android (tanpa tandapetik).

versi April 2014

122

keytool -v -list -keystore C:\Users\user\.android\debug.keystore


Enter keystore password: [ketik android]

Hasilnya akan seperti berikut, ambil hanya nilai MD5 saja.

Dengan nilai certificate fingerprint MD5, kita dapat memperoleh mapkey melalui: (anda
harus memiliki account Google terlebih dulu)
https://developers.google.com/android/maps-api-signup
Masukan fingerprint, klik generate API Key, maka didapatlah API key untuk mengakses
peta.

Selanjutnya buat project baru Android. Saat menentukan target, pilih Google API.
Artinya selain splatform standard, ditambahkan Google API

Langkah pertama adalah merubah manifest.xml, tambahkan ijin untuk mengakses


internet dan lokasi dan menggunakan library google maps. Pastikan <uses-library ..> ada di
dalam <application> .

versi April 2014

123

Selanjutnya isi main.xml dengan code sebagai berikut, ganti isi apiKey dengan key yang
telah diperoleh dari google sebelumnya:

Di activity utama, tambahkan kode berikut, perhatikan bahwa activity diturunkan dari
MapActivity.

Saat program dijalankan, seharusnya akan tampil peta dunia.

Zoom
Menambahkan zoom sangat mudah, tambahkan dua baris berikut ke dalam onCreate.

Ubah Posisi
Untuk mengganti posisi peta, dapat digunakan method setCenter() dengan parameter
GeoPoint. GeoPoint menyimpan posisi latitude dan longitude dalam integer untuk
menghemat memori dan mempercepat proses. Oleh karena itu koordinat perlu dikali 1E6
terlebih dulu. Sedangkan untuk mengatur zoom, dapat digunakan method setZoom.
Tambahkan code berikut pada onCreate:

versi April 2014

124

Menambahkan Layer
Untuk menambahkan layer berupa point di peta, dapat digunakan class ItemizedOverlay.
Class ini berisi informasi objek yang akan ditambahkan dipeta dan aksi jika objek
tersebut ditap.
Tambahkan class baru di project peta kita, beri nama PointsOverlay yang merupakan
turunan dari ItemizedOverlay.

Tambahkan kode berikut

versi April 2014

125

Kemudian di oncreate activity utama, tambahkan kode berikut, set zoom level ke 16.

versi April 2014

126

Grafik 2D
Menggambar di Canvas
Dalam contoh pertama kita akan menggunakan Canvas, Paint, Path dan Color untuk
menggambar kotak. Koordinat canvas 0,0 berada di kiri atas. Makin ke kanan nilai x
semakin besar dan makin kebawah nilai y semakin besar.
Setelah membuat project baru, buatlah class yang bernama GraphicsView yang
merupakan turunan class View.
package com.example.cobagraphicview;
import
import
import
import
import
import

android.content.Context;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.graphics.RectF;
android.view.View;

public class GraphicView extends View {


private RectF kotak = new RectF(100,100,200,200);
Paint cat= new Paint();
public GraphicView(Context context) {
super(context);
}
protected void onDraw(Canvas c) {
cat.setColor(Color.GREEN);
c.drawRect(kotak,cat);
}
}

Lalu di-activity utama, tambahkan kode berikut yang men-set contentview dengan class
GraphicView.

versi April 2014

127

Hasilnya akan seperti ini

Canvas, sesuai namanya adalah tempat untuk menggambar bentuk 2D. Dengan canvas,
kita dapat menggambar bentuk (lingkaran, kotak, garis, titik), menggambar text dan
melakukan operasi translate, scale, rotate.
Paint digunakan untuk menyimpan style, warna dan informasi lainnya yang dibutuhkan
untuk menggambar.
Class Color digunakan untuk merepresentasikan warna. Android menggunakan 4 angka
untuk alpha, red, green dan blue (RGB) dengan masing-masing rentang nilai 0 sd 255.
Alpha digunakan menyatakan transparansi: alpha 0 artinya transparan 100% . Pada code
diatas, kita menggunakan color constant (Color.GREEN). Coba ganti baris tersebut
menjadi, silahkan berkesperimen dengan alpha yang lebih kecil.
cat.setColor(Color.argb(75, 255, 0, 0)); //alphpa,reg,gree,blue

Sekarang kita coba fungsi-fungsi lain pada canvas, tambahkan code berikut dalam class
Graphicsview
package com.example.cobagraphicview;
import
import
import
import
import
import
import

android.content.Context;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.graphics.RectF;
android.graphics.Paint.Style;
android.view.View;

public class GraphicView extends View {

versi April 2014

128

private
private
private
private
private

RectF
RectF
RectF
RectF
RectF

kotak = new RectF(100,150,200,200); //x1,y1,x2,y2


kotak2 = new RectF(200,25,300,75);
kotak3 = new RectF(300,300,400,400);
oval = new RectF(100,200,200,300); //oval akan mengikut rect ini
oval2 = new RectF(100,300,200,400);

private Paint cat= new Paint();

public GraphicView(Context context) {


super(context);
}
protected void onDraw(Canvas c) {
//gambar kotak
cat.setColor(Color.argb(75, 255, 0, 0)); //alpha,red,green,blue
c.drawRect(kotak,cat);
//gambar lingkarang biru
cat.setColor(Color.BLUE);
c.drawCircle(50, 50, 30, cat); //x,y,radius
//gambar kotak dengan ujung membulat
c.drawRoundRect(kotak2, 10, 10, cat); //lokasikotak,x-radius oval, y radius oval
//gambar mulai dari posisi 45 derajat sebanyak 90 derajat searah jarum jam
//lengkungan akan mengikuti rect oval
//paramater ke 4 jika true garis penutup melewati titik pusat
//memberikan efek spt pizza yang dipotong.
c.drawArc(oval, 45, 90, true,cat);
cat.setColor(Color.RED);
//jika parameter ke-4 false maka garis akan melewati
//ujung ke ujung tanpa harus ke titik pusat
//menyebabkan efek spt lingkarang dipotong2 mendatar
c.drawArc(oval2, 45, 90, false,cat);
//gambar garis
c.drawLine(50,500,400,500,cat);

//x1,y1,x2,y2

//gambar kotak kosong


cat.setColor(Color.GREEN);
cat.setStyle(Style.STROKE);
cat.setStrokeWidth(5);
c.drawRect(kotak3,cat);

//gambar titik
cat.setColor(Color.BLACK);
for (int i=0;i<10;i++) {
c.drawPoint( (float) Math.random()*500, (float)Math.random()*500, cat);
}

Hasilnya akan seperti berikut:

versi April 2014

129

versi April 2014

130

Catatan: masih berantakan, harus diperbaiki


TBD penjelasan bahwa hardcode posisi itu harus dihindari (sertakan contoh dijalankan di
resolusi berbeda)
TBD: cara setting selalu landscape
TBD: cara mendapatkan ukuran canvas
Untuk mendapatkan ukuran canvas (API baru):
disp.getSize(size);

mendapatkan ukuran canvas untuk API lama:


try {

disp.getSize(size);
} catch (java.lang.NoSuchMethodError ignore) {
size.x = disp.getWidth();
size.y = disp.getHeight();

DP digunakan untuk mendapatkan ukuran yang konstan pada resolusi yang berbeda-beda.
Tanpa DP, 100 pixel di layar dengan resolusi tinggi akan lebih kecil dibandingkan 100
pixel layar dengan resolusi rendah.
Jadi apa itu dp?
1 dp atau dpi artinya 1 pixel pada density 160 (480 x 800). Jadi misalnya untuk density
240, maka satu 1 dpi menjadi 1.5 pixel.
Untuk mengkonversi dari dp ke pixel:
pengali_density=context.getResources().getDisplayMetrics().density;
real pixels = dp * pengali_density.

Perhatikan bahwa layar Android memiliki resolusi berbeda-beda. Sebagai contoh, 100
point di layar dengan resolusi tinggi akan memiliki panjang berbeda dengan layar resolusi
rendah. Gunakan Canvas.getWidth() dan Canvas.getHeight untuk menghitung panjang
objek yang diinginkan. Misalnya jika kita ingin membuat garis sepanjang setengah layar,
gunakan ukuran getWidth() / 2 sehingga pada resolusi apapun, garis akan selalu
sepanjang setengah layar.
TBD: TouchMOve
TBD: Dragdrop
Ada dua cara penyesuaian: pertama kita ingin ukurannya konsisten (untuk daerah yang
ditouch, panah). Kedua kita ingin agar image membesar dan mengecil mengikuti layar.
TBD: Continues touch (touch down, touch up)

versi April 2014

131

TBD: Membuang actionbar


android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

TBD: Membuat image yang transparan dengan gimp


Mendapat lebar dan panjang dalam pixel
dalam activity
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

diluar activty
WindowManager wm = (WindowManager)
vContext.getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
Point size = new Point();
disp.getSize(size);
width = size.x;
height = size.y;

dp to pixel, memastikan ukuran objek sama walaupun berada di device yg berbeda


sdfdfdf
TypedValue.applyDimensions(int, float, DisplayMetrics) that does this.
Here's how to use it:
// returns the number of pixels for 123.4dip
int value = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 123.4, getResources().getDisplayMetrics());

cara lain
// Maybe store this in a static field?
final float SCALE = getContext().getResources().getDisplayMetrics().density;
// Convert dips to pixels
float valueDips = 16.0f;
int valuePixels = (int)(valueDips * SCALE + 0.5f); // 0.5f for rounding

versi April 2014

132

Todo: Canvas coordinate transformations

Menulis Teks di Canvas


Method drawText dapat digunakan untuk menambahkan teks di canvas, sedangkan Path
dan drawTextOnPath dapat digunakan untuk menggambar teks yang mengikuti jalur
tertentu. Untuk jelasnya, tambahkan code dibawah pada project sebelumnya. Akan
ditampilkan tulisan berwarna merah dan tulisan italic
cat.setColor(Color.RED);
//diisi dalam maupun outline
cat.setStyle(Style.FILL_AND_STROKE);
cat.setStrokeWidth(2);
cat.setTextSize(35);
c.drawText("Hello World", 10, 500, cat);
//teks serif dan italic
cat.setTypeface(Typeface.create(Typeface.SERIF,Typeface.ITALIC));
c.drawText("ini serif italic", 10, 550, cat);

Selanjutnya kita akan membuat lingkarang yang mengikuti suatu jalur menggunakan
class Path. Deklarasikan satu objek ini di luar onDraw:

Dianjurkan untuk membuat objek diluar method onDraw karena onDraw dapat dipanggil
berulang-ulang.
Selanjutnya tambahkan kode berikut, kode ini akan membuat dua tulisan dengan path
berbeda.
path1.moveTo(10,85);
path1.lineTo(250,150);
path1.lineTo(350,300);
cat.setTextSize(25);
//0,0 artinya tidak ada jarak antara tulisan dgn path (offset)
c.drawTextOnPath("tulisan ini mengikuti path", path1, 0, 0, cat);
// gambar tulisan melingkar
//kosongkan path
path1.reset();
//x,y,radius dan berlawan jarumjam (CCW)
path1.addCircle(250, 250, 50, Path.Direction.CCW);
c.drawTextOnPath("ini mengikuti lingkaran", path1, 0, 0, cat);

versi April 2014

133

Hasilnya akan seperti ini:

Kode berikut akan menambahkan kotak yang mengikuti ukuran layar yang
memanfaatkan class Path.
int lebar = c.getWidth();
int tinggi = c.getHeight();
int offset=20; //memberikan efek frame
cat.setColor(Color.RED);
cat.setStyle(Style.STROKE);
cat.setStrokeWidth(10);
//menggunakan path, bisa juga dengan drawRect
path1.reset();
path1.moveTo(0+offset, 0+offset); //kiri atas
path1.lineTo(lebar-offset, 0+offset); //kanan atas
path1.lineTo(lebar-offset, tinggi-offset); //kanan bawah
path1.lineTo(0+offset, tinggi-offset); //kiri bawah
path1.lineTo(0+offset, 0+offset); //kembali ke kiri atas
c.drawPath(path1, cat);

versi April 2014

134

Event Touch
Selanjutnya kita akan mencoba membuat app yang akan menggambar kotak ditempat
pengguna menyentuh layar. Buat project baru dan
tambahkan class baru yang
merupakan turunan dari class View, beri nama GraphicsView. Berikut adalah isi kelas
tersebut yang membersihkan layar dan menggambar kotak pada koordinat sentuhan jari.
package com.example.cobatouch;
import
import
import
import
import

android.content.Context;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.view.View;

public class GraphicsView extends View {


//posisi sentuh
public float posX=-1;
public float posY=-1;
private int offset=25;
private Paint cat = new Paint();
public GraphicsView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas c) {
//clear screen
cat.setColor(Color.BLACK);
c.drawRect(0,0,c.getWidth(),c.getHeight(),cat);
//gambar kotak diposisi yang disentuh
if (posX!=-1) {
cat.setColor(Color.YELLOW);
c.drawRect(posX-offset,posY-offset,posX+offset,posY+offset,cat);
}
}
}

versi April 2014

135

Sedangkan kode untuk MainActivity adalah sebagai berikut. MainActivity


mengimplements onTouchListener agar dapat merespon saat event touch terjadi. Kode
aksi saat event touch ditangani di method onTouch.
package com.example.cobatouch;
import
import
import
import
import

android.os.Bundle;
android.app.Activity;
android.view.MotionEvent;
android.view.View;
android.view.View.OnTouchListener;

public class MainActivity extends Activity implements OnTouchListener{


private GraphicsView gv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gv= new GraphicsView( this);

//set listener agar saat graphicview ditouch


//maka onTouch di kelas ini akan dipanggil
gv.setOnTouchListener(this);
setContentView(gv);

@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: //jari menyentuh layar
//passing posisi ke graphicsview
gv.posX = event.getX();
gv.posY = event.getY();
gv.invalidate(); //draw ulang
break;
case MotionEvent.ACTION_MOVE: //bergerak
break;
case MotionEvent.ACTION_UP: //diangkat
break;
case MotionEvent.ACTION_CANCEL: //batal
break;
default:
break;
}
return true;
}

Catatan:
Untuk menentukan apakah touch terjadi di rect tertentu:
contains(int left, int top, int right, int bottom)
Latihan:
Buat app yang menampilkan gambar tank (atau tentara) mush secara random.
Pengguna harus mentouch lokasi tank tersebut, dan jika tepat maka tank akan
hilang.
versi April 2014

136

Load Image di Canvas


Jika kita ingin meload image (jpg,png) ke dalam canvas, maka file gambar tersebut perlu
dimasukkan ke dalam direktori /res/drawable (hdpi,xhdpi dst), baca kembali pembahasan
icon dalam Actionbar. Dalam contoh berikut digunakan gambar ic_launcher yang sudah
tersedia.
Buat class baru bernama GraphicsView yang merupakan turunan dari View. Class ini
berfungsi menggambar isi dari bitmap bmpGambar.
package com.example.cobaloadbitmap;
import
import
import
import
import

android.content.Context;
android.graphics.Bitmap;
android.graphics.Canvas;
android.graphics.Paint;
android.view.View;

public class GraphicsView extends View {


public Bitmap bmpGambar;
private Paint cat;
public GraphicsView(Context context) {
super(context);
}
protected void onDraw(Canvas c) {
c.drawBitmap(bmpGambar,50,50,cat);
}
}

Sedangkan code mainActivity adalah sebagai berikut.


package com.example.cobaloadbitmap;
import
import
import
import
import
import

android.os.Bundle;
android.app.Activity;
android.content.res.Resources;
android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.view.Menu;

public class MainActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GraphicsView gv = new GraphicsView(this);
//load bitmap
Resources res = getResources();
Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.ic_launcher);

versi April 2014

137

gv.bmpGambar = bmp;
setContentView(gv);
}
}

Hasilnya akan muncul seperti ini

Manipulasi Bitmap
Merubah ukuran bitmap penjelasan
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GraphicsView gv = new GraphicsView(this);
//load bitmap
Resources res = getResources();
//bitmap asal
Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.ic_launcher);
//bitmap copy dari yg pertama, tapi ukurannya jadi 200x200
Bitmap bmp2 = Bitmap.createScaledBitmap(bmp, 200, 200, false);
gv.bmpGambar = bmp2;
setContentView(gv);
}

Merotasi bitmap

TBD:
ubah ukuran image
rotate image
drawable-nodpi

Animasi di Canvas dengan Asynctask


Animasi di canvas cocok digunakan untuk game sederhana seperti game berjenis puzzle
yang melibatkan sedikit objek dan tidak memperlukan animasi berat. Canvas juga lebih
sederhana dibandingkan dengan OpenGL

versi April 2014

138

Animasi dapat dilakukan dengan membersihkan layar dan menggambar objek di tempat
yang baru. Class Asyntask dapat digunakan untuk mengatur posisi objek dan jeda antar
frame. Asyntask melakukan proses dibackground, sehingga app tidak terkunci dan tetap
responsif.
Berikut adalah contoh codenya. Buat project baru, tambahkan class GraphicsView yang
merupakan turunan View seperti pada contoh sebelumnya. Class ini akan membersihkan
layar dan menggambar image sesuai posisi.
package com.example.cobaanimasibmp;
import
import
import
import
import
import

android.content.Context;
android.graphics.Bitmap;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.view.View;

public class GraphicsView extends View{


//posisi bola
public float posX=0;
public float posY=0;
public Bitmap bmpGambar;
private Paint cat = new Paint();
public GraphicsView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas c) {
//clear screen
c.drawColor(Color.WHITE);
//gambar bitmap
c.drawBitmap(bmpGambar,posX,posY,cat);
}
}

Selanjutnya buat class AnimasiTask yang merupakan turunan dari Asynctask. Kelas ini
berperan untuk mengatur posisi objek dan memerintahkan agar canvas didraw ulang
setiap posisi berubah.
package com.example.cobaanimasibmp;
import android.os.AsyncTask;
import android.util.Log;
public class AnimasiTask extends AsyncTask <Void, Void, Void> {
public GraphicsView gv; //tempat animasi digambar
@Override
protected Void doInBackground(Void... arg0) {

versi April 2014

139

// method ini dijalankan di background secara asynchronous


for (int i=10;i<600;i=i+20) {
//bergerak diagonal
gv.posX=i;
gv.posY=i;
//publisgProgress adalah method standard di Asyntask
//dipanggil pada saat loop untuk memberikan kesempatan
//UI untuk mendraw
//contohnya untuk mendraw progressBar
//tapi dalam app ini digunakan untuk mendraw image
//diposisi baru
publishProgress();
//tidur 0.2 detik, agar animasi tdk terlalu cepat
try {
Thread.sleep((long)(1000*0.2));
} catch (InterruptedException e) {
e.printStackTrace();
Log.e("yw","error saat mencoba sleep"+e.getMessage());
}

}
return null;

@Override
protected void onProgressUpdate(Void... progress) {
gv.postInvalidate(); //refresh canvas agar menggambar image di posisi baru
}
}

Terakhir, di-activity utama tambahkan code berikut:


package com.example.cobaanimasibmp;
import
import
import
import
import
import

android.os.Bundle;
android.app.Activity;
android.content.res.Resources;
android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.view.Menu;

public class MainActivity extends Activity {


private GraphicsView gv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gv= new GraphicsView( this);
Resources res = getResources();
Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.ic_launcher);
gv.bmpGambar = bmp;
setContentView(gv);
AnimasiTask at = new AnimasiTask();
at.gv = gv;
at.execute(); //jalankan animasi secara async dan dibackground
}
}

versi April 2014

140

Program menampilkan serangga di layar yang bergerak, jika pengguna memukulnya dengan jari, maka pengguna mendapat skor. Tampilkan animasi jik

Animasi di Canvas dengan Thread


Asynctask ditujukan untuk task dalam periode pendek, dan kontrol pada thread terbatas.
Padahal pada animasi dibutuhkan loop yang terus berulang. Untuk mengatasi hal ini
dapat digunakan thread sendiri. Di dalam thread inilah dilakukan loop update posisi dan
menggambar canvas. Kelemahan dari pendekatan ini adalah code yang relatif lebih rumit.
Program dibagi menjadi tiga class, pertama adalah class GameRunnable yang
mengimplement Runnable, kedua adalah class GameView yang merupakan turunan dari
class SurfaceView dan terakhir adalah activity-nya sendiri.
Berikut adalah kode untuk class GameRunnable. Method run() pada class ini yang akan
dijalankan di thread terpisah. Di dalam method run dilakukan update posisi gambar dan
penggambaran canvas.
import
import
import
import
import
import
import
import
import
import

com.example.animasicanvas2.R;
android.content.Context;
android.content.res.Resources;
android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.graphics.Canvas;
android.graphics.Color;
android.graphics.Paint;
android.util.Log;
android.view.SurfaceHolder;

//menggunakan runnable, karena hanya run yang dibutuhkan untuk dioverride


//baca: http://manikandanmv.wordpress.com/tag/extends-thread-vs-implements-runnable/
//tentang bedanya extends thread vs impelements runnable
public class GameRunnable implements Runnable {
//jika true, loop di run() berakhir
boolean mRun=false;
float posX=10;
float posY=100;
Bitmap bmp;

versi April 2014

141

private Paint cat = new Paint();


//akses ke surface dan canvas
private SurfaceHolder mSurfaceHolder;
//akses ke context (untuk ambil resource)
Context mContext;
private void updatePosisi() {
//geser ke kiri dan kalau sudah max, kembali ke awal
posX= posX+10;
if (posX>200) {
posX=10;
}
//tidur 0.2 detik, agar animasi tdk terlalu cepat
try {
Thread.sleep((long)(1000*0.2));
} catch (InterruptedException e) {
e.printStackTrace();
Log.e("yw","error saat mencoba sleep"+e.getMessage());
}
}

//siapkan resources
public GameRunnable(SurfaceHolder vSurfaceHolder, Context vContext) {
mSurfaceHolder = vSurfaceHolder;
mContext = vContext;
Resources res = mContext.getResources();
bmp = BitmapFactory.decodeResource(res, R.drawable.ic_launcher);
}
//bersihkan layar dan gambar objek
public void doDraw(Canvas c) {
//canvas perlu dicek, karena pada saat
//user pindah ke activity lain, c bisa
//berisi null (proses shutdown belum selesai dan
//thread masih jalan, tapi canvas sudah didestroy)
if (c!=null) {
//clear screen
c.drawColor(Color.WHITE);
//gambar bitmap
c.drawBitmap(bmp,posX,posY,cat);
}
}

@Override
public void run() {
//loop forever selama tidak dishutdown (mRun diset false)
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
updatePosisi();

versi April 2014

142

doDraw(c);
}
} finally {
//kalau ada masalah
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
//jika diset false maka akan shutdown (lihat method run())
public void setRunning(boolean b) {
mRun = b;
}
}

Bagian kedua adalah class GameView yang merupakan turunan dari SurfaceView. Dalam
class ini thread dimulai saat surface dicreate dan dishutdown saat surface didestroy.
import android.content.Context;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
//surfaceView digunakan karena GUI akan seriung diupdate
//dan cepat untuk animasi
public class GameView extends SurfaceView implements SurfaceHolder.Callback {

public Thread mThread;


private GameRunnable gr;

public void startThread() {


//runnable jadi parameter thread
mThread = new Thread(gr);
gr.setRunning(true);
//saat thread dimulai, maka GameRunnable.run() dipanggil
mThread.start();
}
public void shutDownThread() {
boolean retry = true;
gr.setRunning(false); //matikan,
//loop terus sampai thread berhenti
//setRunning(false) tidak menghentikan seketika
//coba lihat method GameThread.run()
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {

versi April 2014

143

}
}
}
public GameView(Context context) {
super(context);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
gr = new GameRunnable(holder,context);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// jalankan thread saat surface sudah ada
startThread();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
shutDownThread();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// bisa digunakan untuk memberi tahu GameThread ada perubahan dimensi
// surface
}
}

Bagian yang terakhir adalah Activity biasa. Pada class ini GameView dicreate dan
ditampilkan.
import com.example.animasicanvas2.R;
import android.os.Bundle;
import android.app.Activity;
public class MainActivity extends Activity {
GameView gv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gv= new GameView(this);
setContentView(gv);
}
@Override
protected void onPause() {
super.onPause();
//nantinya perlu diisi dengan penyimpanan state
//melalui bundle
}
@Override

versi April 2014

144

protected void onResume() {


super.onResume();
//nantinya perlu diisi dengan load state
}
}

Animasi dengan Multibitmap


Pada kode sebelumnya, kita telah membuat animasi menggunakan thread. Masalahnya
efek animasi tidak terlalu terlihat karena hanya satu jenis image yang digunakan. Pada
bagian ini kita akan menggunakan dua jenis image yang ditampilkan secara bergantian
sehingga memberikan efek orang berjalan.
200 pixels

200 pixels

100 pixels 100 pixels

public GameRunnable(SurfaceHolder vSurfaceHolder, Context vContext) {


mSurfaceHolder = vSurfaceHolder;
mContext = vContext;
Resources res = mContext.getResources();
//bmp berisi semua frame ada dalam satu image
bmp = BitmapFactory.decodeResource(res, R.drawable.orang);
}

versi April 2014

145

Game Loop
Kelemahan: constant frame rate.
http://gafferongames.com/game-physics/fix-your-timestep/
http://www.koonsolo.com/news/dewitters-gameloop/
http://obviam.net/index.php/the-android-game-loop/
http://gamedev.stackexchange.com/questions/1589/fixed-time-step-vs-variable-time-step

Program menampilkan serangga di layar yang bergerak, jika pengguna memukulnya dengan jari, maka pengguna mendapat skor. Tampilkan animasi jik

TBD: Transparent image gimp

Latihan:
TBD: Kotak yang saat diklik maka akan keluar boneka dari dalam kotak tersebut

versi April 2014

146

Anda mungkin juga menyukai