Activity
Activity merupakan salah satu komponen penting Android yang berfungsi untuk menampilkan user interface ke layar pengguna. Ini seperti pada saat Anda melihat daftar percakapan pada aplikasi chat atau daftar email pada aplikasi Gmail di ponsel Android Anda. Di dalamnya Anda dapat berinteraksi dengan aplikasi Anda, baik dengan menekan tombol atau menampilkan list.
Seperti ketika Anda membuat project baru di Android Studio, biasanya akan ada dua berkas yang sudah tercipta, yaitu MainActivity dan activity_main.xml.
MainActivity ini disebut sebagai class Activity karena mewarisi (extends) superclass Activity. Tugasnya yaitu menampilkan layout activity_main.xml dan mengelola interaksi yang ada di dalamnya.
Umumnya dalam sebuah aplikasi terdapat lebih dari satu activity yang saling terhubung dengan tugas yang berbeda-beda. Yang perlu diperhatikan yaitu setiap Activity harus terdaftar di AndroidManifest.xml.
Umumnya dalam sebuah aplikasi terdapat lebih dari satu activity yang saling terhubung dengan tugas yang berbeda-beda. Yang perlu diperhatikan yaitu setiap Activity harus terdaftar di AndroidManifest.xml.
Secara default, ia akan didaftarkan jika Anda membuat Activity baru dengan cara otomatis. Caranya yaitu klik kanan pada nama package → New → Activity → pilih template Activity yang tersedia.
Untuk lebih mendalami activity, kami menyarankan Anda untuk membaca referensi berikut:
Activity Lifecycle
Activity memiliki daur hidup (lifecycle) dalam sebuah stack pada virtual sandbox yang disiapkan oleh Dalvik Virtual Machine (DVM) atau Android Runtime (ART) yang bersifat last in first out.
Developer yang baik harus mengetahui secara detail tentang life cycle sebuah activity. Terutama untuk melakukan aksi yang tepat, saat terjadi perubahan state activity.
Callback methods yang ada dapat digunakan untuk melakukan beragam proses terkait state dari activity.
Misalnya melakukan semua inisialisasi komponen di onCreate(), melakukan disconnect terhadap koneksi ke server pada onStop() atau onDestroy() dan lain sebagainya.
Pemahaman yang baik tentang daur hidup activity akan membuat implementasi rancangan aplikasi Anda menjadi lebih baik. Hal ini juga akan meminimalisir terjadinya error/bug/force close yang tidak diinginkan.
Pemahaman yang baik tentang daur hidup activity akan membuat implementasi rancangan aplikasi Anda menjadi lebih baik. Hal ini juga akan meminimalisir terjadinya error/bug/force close yang tidak diinginkan.
Last In, First Out (LIFO)
Gambar 1 | Gambar 2 | Gambar 3 |
Aktif: Activity 1 onCreate() → onStart() → onResume() | Aktif: Activity 2 Stack append: Activity 2 [ onResume() ] | Activity 1 onStop() → onRestart() → onStart() → onResume() |
Aksi: Klik Button1 (Pindah) | Aksi: Klik Hardware Back Button | Aktif: Activity 1 |
Stack append: Activity 1 [ onStop() ] | Activity 2 [ finish() ] Stack pop: Activity 2 [ onDestroy() ] |
- Gambar 1
Jika Anda memiliki sebuah aplikasi yang terdiri dari 2 activity, maka activity pertama akan dijalankan setelah pengguna meluncurkan aplikasi melalui ikon aplikasi di layar device. Activity yang ada saat ini berada pada posisi activity running setelah melalui beberapa state onCreate (created) → onStart (started) → onResume (resumed) dan masuk ke dalam sebuah stack activity.
Bila pada activity pertama Anda menekan sebuah tombol untuk menjalankan activity kedua, maka posisi state dari activity pertama berada pada posisi stop. Saat itu, callback onStop() pada activity pertama akan dipanggil.
Ini terjadi karena activity pertama sudah tidak berada pada layar foreground / tidak lagi ditampilkan. Semua informasi terakhir pada activity pertama akan disimpan secara otomatis.
Sementara itu, activity kedua masuk ke dalam stack dan menjadi activity terakhir yang masuk. - Gambar 2
Activity kedua sudah muncul di layar sekarang. Ketika Anda menekan tombol back pada physical button menu utama atau menjalankan metode finish(), maka activity kedua Anda akan dikeluarkan dari stack.
Pada kondisi di atas, state activity kedua akan berada pada destroy. Oleh karenanya, metode onDestroy() akan dipanggil.
Kejadian keluar dan masuk stack pada proses di atas menandakan sebuah model Last In, First Out. Activity kedua menjadi yang terakhir masuk stack (Last In) dan yang paling pertama keluar dari stack (First Out). - Gambar 3Activity Pertama akan dimunculkan kembali di layar setelah melalui beberapa state dengan rangkaian callback method yang terpanggil, onStop → onRestart → onStart → onResume.
Detailnya dapat Anda baca di sini:
Saving Activity State
Ketika sebuah activity mengalami pause kemudian resume, maka state dari sebuah activity tersebut dapat terjaga. Sebabnya, obyek activity masih tersimpan di memory sehingga dapat dikembalikan state-nya.
Dengan menjaga state dari activity, maka ketika activity tersebut ditampilkan, kondisinya akan tetap sama dengan kondisi sebelumnya.
Akan tetapi ketika sistem menghancurkan activity untuk keperluan memori misalnya karena memori habis, maka obyek activity dihancurkan. Alhasil, ketika activity ingin ditampilkan kembali diperlukan proses re-create activity yang dihancurkan tadi.
Kejadian di atas adalah hal yang lumrah terjadi. Oleh karena itu, perubahan yang terjadi pada activity perlu disimpan terlebih dahulu sebelum ia dihancurkan. Di sinilah metode onSaveInstanceState() digunakan.
Dalam onSaveInstanceState terdapat bundle yang dapat digunakan untuk menyimpan informasi. Informasi dapat disimpan dengan memanfaatkan fungsi seperti putString() dan putInt().
Ketika activity di-restart, bundle akan diberikan kepada metode onCreate dan onRestoreInstanceState. Bundle tersebut akan dimanfaatkan untuk mengembalikan kembali perubahan yang telah terjadi sebelumnya.
Proses penghancuran activity dapat juga terjadi ketika terdapat perubahan konfigurasi seperti perubahan orientasi layar (portrait-landscape), keyboard availability, dan perubahan bahasa.
Penghancuran ini akan menjalankan callback method onDestroy dan kemudian menjalankan onCreate. Penghancuran ini dimaksudkan agar activity dapat menyesuaikan diri dengan konfigurasi baru yang muncul pada kejadian-kejadian sebelumnya.
Hal yang perlu diingat ketika menggunakan onSaveInstanceState adalah untuk tidak menyimpan data yang besar pada bundle. Contohnya, hindari penyimpanan data bitmap pada bundle.
Bila data pada bundle berukuran besar, proses serialisasi dan deserialisasi akan memakan banyak memori.
Tujuan
Codelab ini bertujuan untuk mengimplementasikan komponen activity pada aplikasi pertama yang Anda bangun. Harapannya codelab ini dapat memberi gambaran yang jelas tentang cara kerja activity.
Codelab pertama adalah dengan membuat aplikasi yang dapat menghitung volume balok. Seperti ini tampilannya:
Logika Dasar
Melakukan input ke dalam objek EditText → melakukan validasi input → menghitung volume balok ketika tombol hitung diklik.
Codelab Membuat Proyek Baru
- Buat proyek baru dengan klik File → New → New Project pada Android Studio Anda atau Anda bisa memilih Start a new Android Studio project di bagian dashboard.
- Pada bagian ini kita akan memilih tipe activity awal dari template yang telah disediakan. Saat ini Android Studio sudah menyediakan berbagai macam template activity dari yang paling sederhana hingga yang paling kompleks seperti:
Selain itu, Anda juga bisa memilih target device mana yang akan Anda buat seperti Phone and Tablet, Wear OS, TV, Android Auto atau Android Things.Jenis-jenis template Activity Fungsinya Add No Activity Tidak ada activity yang ditambahkan Basic Activity Activity dengan template komponen material design seperti FloatingActionButton Bottom Navigation Activity Activity dengan tampilan side bar menu di bagian bawah Empty Activity Activity dalam bentuk yang paling dasar Fragment + ViewModel Activity dengan menerapkan architecture component Fullscreen Activity Activity fullscreen tanpa status bar Google AdMob Ads Activity Activity dengan konfigurasi default iklan Admob Google Maps Activity Activity dengan menyediakan konfigurasi dasar Google Maps Login Activity Activity untuk halaman login Master / Detail Flow Activity yang diperuntukan untuk alur aplikasi master detail pada peranti tablet Navigation Drawer Activity Activity dengan tampilan side bar menu Scrolling Activity Activity dengan kemampuan scroll konten didalamnya secara vertikal Settings Activity Activity yang diperuntukan untuk konfigurasi aplikasi Tabbed Activity Activity yang diperuntukan untuk menampilkan lebih dari satu tampilan, dapat digeser ke kanan dan ke kiri (swipe) dengan menggunakan komponen ViewPager
Saat ini kita pilih tipe Empty Activity, klik Next untuk melanjutkan. - Selanjutnya masukkan nama aplikasi dan nama package aplikasi Anda. Sebaiknya jangan sama dengan apa yang ada di contoh, karena ini berfungsi sebagai id dari aplikasi yang Anda buat. Kemudian Anda bisa menentukan lokasi proyek yang akan Anda buat. Setelah itu pilih tipe gawai/peranti (device) untuk aplikasi beserta target minimum SDK yang akan digunakan. Pilihan target Android SDK akan mempengaruhi banyaknya peranti yang dapat menggunakan aplikasi. Di sini kita memilih nilai minimum SDK kita pasang ke Level 21 (Lollipop). Klik Finish untuk melanjutkan.
Catatan: Untuk Android Studio versi 3.4.1 ke bawah, penggunaan AndroidX belum menjadi default. Jadi, silakan beri tanda centang pada Use AndroidX artifacts di setiap kali membuat project. Informasi lebih detail mengenai AndroidX bisa Anda lihat di sini, dan untuk melihat perubahan antara sebelum dan sesudah AndroidX atau cara migrasi menggunakan AndroidX bisa lihat di sini. Perlu Anda ketahui juga, ketika Anda sudah menggunakan AndroidX maka Anda tidak bisa menambahkan library lama atau sebelum AndroidX.
Kelas ini menggunakan bahasa Kotlin sebagai bahasa utama. Namun jika anda ingin menggunakan bahasa Java, ubahlah languages dari Kotlin menjadi Java. Jangan khawatir, di dalam tutorial ini kalian bisa melihat kode dalam bahasa Kotlin dan Java secara berdampingan. - Tampilan layar Anda akan seperti contoh di bawah ini:
- Di sebelah kanan Anda adalah workspace di mana Activity anda berada dan bernama MainActivity dengan layout-nya activity_main.xml. Di sebelah kiri Anda terdapat struktur proyek, di mana nanti kita akan banyak menambahkan berbagai komponen baru, asset, dan library. Untuk lebih mengenal Android Studio lebih dalam silakan baca materi di sini.
Selanjutnya kita akan mulai melakukan pengkodean aplikasi atau lebih enaknya disebut ngoding.
Berikut flow umumnya:
- Ngoding Layout untuk user interface aplikasi
- Ngoding Activity untuk menambahkan logika aplikasi
Untuk mengoptimalkan proses pengetikan, Anda dapat memanfaatkan code completion dengan menekan ctrl + space. Android Studio juga akan mengimpor package dari komponen yang digunakan.
Dilarang Keras untuk copy - paste!
Ngoding pelan-pelan akan membuat Anda lebih jago di masa depan.
Selamat ngoding!
Codelab Layouting
Menambahkan Code Sederhana pada Layout Activity
- Silakan pilih tab berkas activity_main.xml pada workspace Anda(res/layout/activity_main.xml).
Pastikan project window pada pilihan Android, seperti di bawah ini:
Maka akan ada tampilan seperti ini, kemudian pilih tab Code di sebelah pojok kanan atas.
Dan tambahkan baris-baris berikut:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="16dp"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Panjang" />
- <EditText
- android:id="@+id/edt_length"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Lebar" />
- <EditText
- android:id="@+id/edt_width"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Tinggi" />
- <EditText
- android:id="@+id/edt_height"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <Button
- android:id="@+id/btn_calculate"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Hitung" />
- <TextView
- android:id="@+id/tv_result"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="Hasil"
- android:textSize="24sp"
- android:textStyle="bold" />
- </LinearLayout>
- Perlu diperhatikan root layout (tag layout terluar) yang dipakai di sini adalah LinearLayout. Jika kita menggunakan Android Studio versi 3 ke atas maka secara default root yang dipakai adalah ConstraintLayout. Agar sesuai dengan latihan ini, kita tinggal menggantinya menjadi LinearLayout. Untuk materi tentang Layout akan dibahas nanti pada modul yang berbeda.
- Kemudian akan muncul warning pada atribut android:text pada layout tersebut.
Ini karena kita melakukan hardcoding pada nilai string-nya. Mari kita hilangkan code warning tersebut dengan menekan Alt+Enter (option + return pada Mac) atau menekan lampu kuning yang muncul pada attribute android:text.
Akan muncul dialog seperti ini, pilih extract string resource. - Kemudian akan muncul dialog seperti di bawah ini. Sesuaikan dengan nama yang ada.
- Fungsi extract string resource akan secara otomatis menambahkan nilai dari android:text ke dalam berkas res → values → strings.xml.
Lakukan hal yang sama pada komponen view lainnya hingga tidak ada warning lagi. Jika kita buka berkas strings.xml, maka isinya akan menjadi seperti ini:- <resources>
- <string name="app_name">BarVolume</string>
- <string name="width">Lebar</string>
- <string name="height">Tinggi</string>
- <string name="calculate">Hitung</string>
- <string name="result">Hasil</string>
- <string name="length">Panjang</string>
- </resources>
- Maka kode di dalam activity_main.xml akan menjadi seperti ini:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="16dp"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/length" />
- <EditText
- android:id="@+id/edt_length"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/width" />
- <EditText
- android:id="@+id/edt_width"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/height" />
- <EditText
- android:id="@+id/edt_height"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:lines="1" />
- <Button
- android:id="@+id/btn_calculate"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/calculate" />
- <TextView
- android:id="@+id/tv_result"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@string/result"
- android:textSize="24sp"
- android:textStyle="bold" />
- </LinearLayout>
- Jika Anda perhatikan, hasil layout sementara akan menjadi seperti ini:
Selain menggunakan Teks seperti di atas, Anda juga dapat membuat layout dengan menggunakan design. Untuk tutorialnya dapat Anda lihat divideo berikut:
Codelab Kode Logika
Menambahkan Kode Logika Sederhana pada MainActivity.
- Selanjutnya setelah selesai, lanjutkan dengan membuka berkas MainActivity dan lanjutkan ngoding baris-baris di bawah ini.
Tambahkan beberapa variabel yang akan digunakan untuk menampung view.
- private lateinit var edtWidth: EditText
- private lateinit var edtHeight: EditText
- private lateinit var edtLength: EditText
- private lateinit var btnCalculate: Button
- private lateinit var tvResult: TextView
- private EditText edtWidth;
- private EditText edtHeight;
- private EditText edtLength;
- private Button btnCalculate;
- private TextView tvResult;
Kemudian inisiasi variabel yang telah kita buat dengan menambahkan kode berikut di dalam metode onCreate.
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- edtWidth = findViewById(R.id.edt_width)
- edtHeight = findViewById(R.id.edt_height)
- edtLength = findViewById(R.id.edt_length)
- btnCalculate = findViewById(R.id.btn_calculate)
- tvResult = findViewById(R.id.tv_result)
- btnCalculate.setOnClickListener(this)
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- edtWidth = findViewById(R.id.edt_width);
- edtHeight = findViewById(R.id.edt_height);
- edtLength = findViewById(R.id.edt_length);
- btnCalculate = findViewById(R.id.btn_calculate);
- tvResult = findViewById(R.id.tv_result);
- btnCalculate.setOnClickListener(this);
- }
Akan muncul baris merah pada kata this. Hal ini karena kita belum menambahkan interface di kelas MainActivity. Silakan klik di atas baris merah tersebut, kemudian tekan tombol Alt + Enter (option + return pada Mac) atau menekan lampu merah yang muncul lalu pilih aksi berikut untuk implement interface.
Maka secara otomatis akan ada penambahan kode pada kelas MainActivity seperti berikut ini:
- class MainActivity : AppCompatActivity(), View.OnClickListener {
- ...
- }
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- ...
- }
Jika terdapat baris merah seperti ini:
Jangan khawatir! Silakan klik di atas baris merah tersebut, kemudian tekan tombol Alt + Enter (option + return pada Mac) atau menekan lampu merah yang muncul lalu pilih implement members (Kotlin) atau implement methods (Java).
Jika terdapat baris merah seperti ini:
Maka secara otomatis akan ada penambahan metode onClick di kelas MainActivity. Setelah itu, tambahkan kode berikut ke dalam metode onClick:
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- ...
- }
- override fun onClick(v: View) {
- if (v.id == R.id.btn_calculate) {
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- val volume = inputLength.toDouble() * inputWidth.toDouble() * inputHeight.toDouble()
- tvResult.text = volume.toString()
- }
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ...
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.btn_calculate) {
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
- double volume = Double.valueOf(inputLength) * Double.valueOf(inputWidth) * Double.valueOf(inputHeight);
- tvResult.setText(String.valueOf(volume));
- }
- }
Akhirnya kelas MainActivity akan memiliki kode seperti berikut ini:
- class MainActivity : AppCompatActivity(), View.OnClickListener {
- private lateinit var edtWidth: EditText
- private lateinit var edtHeight: EditText
- private lateinit var edtLength: EditText
- private lateinit var btnCalculate: Button
- private lateinit var tvResult: TextView
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- edtWidth = findViewById(R.id.edt_width)
- edtHeight = findViewById(R.id.edt_height)
- edtLength = findViewById(R.id.edt_length)
- btnCalculate = findViewById(R.id.btn_calculate)
- tvResult = findViewById(R.id.tv_result)
- btnCalculate.setOnClickListener(this)
- }
- override fun onClick(v: View) {
- if (v.id == R.id.btn_calculate) {
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- val volume = inputLength.toDouble() * inputWidth.toDouble() * inputHeight.toDouble()
- tvResult.text = volume.toString()
- }
- }
- }
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- private EditText edtWidth, edtHeight, edtLength;
- private Button btnCalculate;
- private TextView tvResult;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- edtWidth = findViewById(R.id.edt_width);
- edtHeight = findViewById(R.id.edt_height);
- edtLength = findViewById(R.id.edt_length);
- btnCalculate = findViewById(R.id.btn_calculate);
- tvResult = findViewById(R.id.tv_result);
- btnCalculate.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.btn_calculate) {
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
- double volume = Double.valueOf(inputLength) * Double.valueOf(inputWidth) * Double.valueOf(inputHeight);
- tvResult.setText(String.valueOf(volume));
- }
- }
- }
- telah selesai, silakan jalankan aplikasi dengan memilih menu Run → Run ‘app’ dari menu bar.
Selain cara di atas, Anda juga dapat menekan icon berikut di toolbar:
Kemudian akan muncul pilihan seperti ini:
Itu tandanya ADB (Android Debugger) pada peranti yang Anda punya telah terhubung dengan Android Studio. Jika Anda tidak memiliki peranti, maka Anda dapat menggunakan emulator. Ikuti materinya di modul sebelumnya atau lihat materi di sini.
Kami merekomendasikan Anda menggunakan peranti Android sewaktu mengembangkan aplikasi. Selain karena beban memori pada peranti Anda akan jadi lebih rendah, pendekatan ini juga akan memungkinkan Anda untuk merasakan bagaimana aplikasi berjalan di device sebenarnya. - Pilih OK untuk menjalankan dan tunggu hingga proses building dan instalasi APK selesai. Jika sudah, seharusnya hasilnya akan seperti ini:
- Silakan masukkan nilai panjang, lebar, dan tinggi kemudian tekan tombol Hitung dan hasilnya akan ditampilkan di objek textview tvResult. Namun masih ada sedikit masalah di sini, yaitu Anda tetap melakukan proses perhitungan walaupun salah satu nilainya kosong. Hal ini akan menyebabkan aplikasi force close karena perhitungan tidak dapat diproses. Maka untuk mengatasinya Anda akan menggunakan percabangan untuk mengecek apakah masing-masing EditText kosong atau tidak.
- Silakan buka kembali kelas MainActivity. Tambahkan kode berikut ke dalam metode onClicksebelum melakukan perhitungan.
- override fun onClick(v: View) {
- if (v.id == R.id.btn_calculate) {
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- var isEmptyFields = false
- if (inputLength.isEmpty()) {
- isEmptyFields = true
- edtLength.error = "Field ini tidak boleh kosong"
- }
- if (inputWidth.isEmpty()) {
- isEmptyFields = true
- edtWidth.error = "Field ini tidak boleh kosong"
- }
- if (inputHeight.isEmpty()) {
- isEmptyFields = true
- edtHeight.error = "Field ini tidak boleh kosong"
- }
- if (!isEmptyFields) {
- val volume = inputLength.toDouble() * inputWidth.toDouble() * inputHeight.toDouble()
- tvResult.text = volume.toString()
- }
- }
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.btn_calculate) {
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
- boolean isEmptyFields = false;
- if (TextUtils.isEmpty(inputLength)) {
- isEmptyFields = true;
- edtLength.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputWidth)) {
- isEmptyFields = true;
- edtWidth.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputHeight)) {
- isEmptyFields = true;
- edtHeight.setError("Field ini tidak boleh kosong");
- }
- if (!isEmptyFields) {
- double volume = Double.valueOf(inputLength) * Double.valueOf(inputWidth) * Double.valueOf(inputHeight);
- tvResult.setText(String.valueOf(volume));
- }
- }
- }
Akhirnya kelas MainActivity akan memiliki kode seperti berikut ini:
- class MainActivity : AppCompatActivity(), View.OnClickListener {
- private lateinit var edtWidth: EditText
- private lateinit var edtHeight: EditText
- private lateinit var edtLength: EditText
- private lateinit var btnCalculate: Button
- private lateinit var tvResult: TextView
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- edtWidth = findViewById(R.id.edt_width)
- edtHeight = findViewById(R.id.edt_height)
- edtLength = findViewById(R.id.edt_length)
- btnCalculate = findViewById(R.id.btn_calculate)
- tvResult = findViewById(R.id.tv_result)
- btnCalculate.setOnClickListener(this)
- }
- override fun onClick(v: View) {
- if (v.id == R.id.btn_calculate) {
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- var isEmptyFields = false
- if (inputLength.isEmpty()) {
- isEmptyFields = true
- edtLength.error = "Field ini tidak boleh kosong"
- }
- if (inputWidth.isEmpty()) {
- isEmptyFields = true
- edtWidth.error = "Field ini tidak boleh kosong"
- }
- if (inputHeight.isEmpty()) {
- isEmptyFields = true
- edtHeight.error = "Field ini tidak boleh kosong"
- }
- if (!isEmptyFields) {
- val volume = inputLength.toDouble() * inputWidth.toDouble() * inputHeight.toDouble()
- tvResult.text = volume.toString()
- }
- }
- }
- }
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- private EditText edtWidth, edtHeight, edtLength;
- private Button btnCalculate;
- private TextView tvResult;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- edtWidth = findViewById(R.id.edt_width);
- edtHeight = findViewById(R.id.edt_height);
- edtLength = findViewById(R.id.edt_length);
- btnCalculate = findViewById(R.id.btn_calculate);
- tvResult = findViewById(R.id.tv_result);
- btnCalculate.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.btn_calculate) {
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
- boolean isEmptyFields = false;
- boolean isInvalidDouble = false;
- if (TextUtils.isEmpty(inputLength)) {
- isEmptyFields = true;
- edtLength.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputWidth)) {
- isEmptyFields = true;
- edtWidth.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputHeight)) {
- isEmptyFields = true;
- edtHeight.setError("Field ini tidak boleh kosong");
- }
- if (!isEmptyFields) {
- double volume = Double.valueOf(inputLength) * Double.valueOf(inputWidth) * Double.valueOf(inputHeight);
- tvResult.setText(String.valueOf(volume));
- }
- }
- }
- }
- Jalan kembali aplikasi Anda dengan memilih menu Run → Run ‘app’ atau shortcut Shift + F10. Cobalah langsung menekan tombol HITUNG tanpa mengisi EditText, maka aplikasi Anda tidak akan force close dan akan muncul peringatan bahwa "Field ini tidak boleh kosong".
- Apakah kita sudah selesai? Belum! Masih ada yang kurang. Ketika nilai volume sudah dihitung dan kemudian terjadi pergantian orientasi (portrait-landscape) pada peranti, maka hasil perhitungan tadi akan hilang. Hal ini karena di dalam Android, jika melakukan pergantian orientasi, Android akan memanggil fungsi onCreate kembali, sehingga data akan kembali menjadi seperti semula.
Untuk mengatasinya, tambahkan metode onSaveInstanceState() pada MainActivity dan sesuaikan seperti berikut:
- companion object {
- private const val STATE_RESULT = "state_result"
- }
- ...
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- outState.putString(STATE_RESULT, tvResult.text.toString())
- }
- private static final String STATE_RESULT = "state_result";
- ...
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString(STATE_RESULT, tvResult.getText().toString());
- }
Kemudian tambahkan juga beberapa baris berikut pada baris terakhir metode onCreate
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- ...
- if (savedInstanceState != null) {
- val result = savedInstanceState.getString(STATE_RESULT) as String
- tvResult.text = result
- }
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ...
- if (savedInstanceState != null) {
- String result = savedInstanceState.getString(STATE_RESULT);
- tvResult.setText(result);
- }
- }
- Silakan jalankan kembali aplikasinya. Ulangi proses perhitungan seperti sebelumnya. Kemudian ganti orientasi peranti Anda. Jika sudah benar maka hasil perhitungan tidak akan hilang.
Bedah Kode
Pembahasan tentang layout xml
Layout merupakan user interface dari suatu activity. Layout dituliskan dalam format xml (extensible markup language).
- xml version="1.0" encoding="utf-8"?>
Baris ini mengidentifikasi bahwa berkas ini berformat xml.
- xmlns:android="http://schemas.android.com/apk/res/android"
Kode di atas menandakan namespace yang digunakan dalam keseluruhan berkas xml ini.
Macam Views
Di sini kita menggunakan beberapa komponen user interface yang disebut view. Di antaranya:
- TextView, merupakan komponen view untuk menampilkan teks ke layar.
- EditText, merupakan komponen view untuk memberikan input teks.
- Button, merupakan komponen view untuk melakukan sebuah aksi klik.
- LinearLayout, merupakan komponen view bertipe viewgroup yang menjadi parent dari semua sub komponen view (sub view) di dalamnya. Komponen ini bersifat sebagai kontainer untuk komponen lain dengan orientasi secara vertikal atau horizontal.
Cara membaca:
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/calculate"
- android:layout_marginBottom="16dp"/>
Komponen di atas adalah sebuah TextView. Perhatikan gambar di bawah ini. Warna ungu menandakan namespace yang digunakan; warna biru adalah atribut dari komponen dan warna hijau adalah nilai dari atribut. Penjelasannya seperti di bawah ini:
- match_parent, merupakan sebuah ukuran dimensi sebuah View yang disesuaikan dengan ukuran layar baik secara horizontal pada layout_width dan vertikal jika pada layout_height.
- wrap_content, merupakan ukuran dimensi sebuah View yang disesuaikan dengan ukuran konten di dalamnya baik secara horizontal pada layout_width dan vertikal jika pada layout_height.
- @string/calculate, merupakan sebuah value calculate berasal dari berkas strings.xml.
Penggunaan centralize resource value akan memudahkan Anda sewaktu mengembangkan aplikasi Android. Cara tersebut digunakan agar Anda tidak menulis nilai yang sama berulang-ulang.
Apa itu @+id/ ?
Salah satu contoh penerapan penggunaan @+id/ sebagai berikut:
- <Button
- android:id="@+id/btn_calculate"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/calculate"/>
Penjelasannya sebagai berikut:
- android:id="@+id/btn_calculate"
Jika kita memberikan id pada sebuah view maka kita telah memberikan identifier untuk view tersebut. Pemberian id ini dimaksudkan agar kita bisa melakukan manipulasi/pengendalian pada level logic di komponen seperti activity atau fragment.
Id di atas akan diciptakan di berkas R.java dan disimpan dalam bentuk hexa bertipe data integer, public static final int btn_calculate=0x7f0b0057.
Acuan untuk menyusun tampilan pada RelativeLayout akan dibahas pada modul selanjutnya.
Pembahasan tentang Logika Kode
Kode logika dituliskan ke dalam kelas Kotlin atau Java. Di sinilah semua aktifitas dari suatu aplikasi berjalan.
Activity
- class MainActivity : AppCompatActivity()
- public class MainActivity extends AppCompatActivity
Menandakan bahwa kelas Java di atas merupakan sebuah activity karena inherit (turunan) dari superclass bernama AppCompatActivity.
OnClickListener
- , View.OnClickListener
- implements View.OnClickListener
Ini adalah listener yang kita implementasikan untuk memantau kejadian klik pada komponen tombol (button).
Views
- private lateinit var edtWidth: EditText
- private lateinit var edtHeight: EditText
- private lateinit var edtLength: EditText
- private lateinit var btnCalculate: Button
- private lateinit var tvResult: TextView
- private EditText edtWidth;
- private EditText edtHeight;
- private EditText edtLength;
- private Button btnCalculate;
- private TextView tvResult;
Kode di atas mendeklarasikan semua komponen view yang akan dimanipulasi. Kita deklarasikan secara global agar bisa dikenal di keseluruhan bagian kelas.
OnCreate
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- edtWidth = findViewById(R.id.edt_width)
- edtHeight = findViewById(R.id.edt_height)
- edtLength = findViewById(R.id.edt_length)
- btnCalculate = findViewById(R.id.btn_calculate)
- tvResult = findViewById(R.id.tv_result)
- btnCalculate.setOnClickListener(this)
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- edtWidth = findViewById(R.id.edt_width);
- edtHeight = findViewById(R.id.edt_height);
- edtLength = findViewById(R.id.edt_length);
- btnCalculate = findViewById(R.id.btn_calculate);
- tvResult = findViewById(R.id.tv_result);
- btnCalculate.setOnClickListener(this);
- }
Metode onCreate() merupakan metode utama pada activity. Di sinilah kita dapat mengatur layout xml. Semua proses inisialisasi komponen yang digunakan akan dijalankan di sini.
Inisialisasi komponen dengan findViewById berfungsi untuk menghubungkan variabel yang kita buat sebelumnya dengan id yang sudah kita buat di dalam layout activity_main.xml.
SetContentView
- setContentView(R.layout.activity_main)
- setContentView(R.layout.activity_main);
Maksud baris di atas adalah kelas MainActivity akan menampilkan tampilan yang berasal dari layout activity_main.xml.
Casting View
- edtWidth = findViewById(R.id.edt_width)
- edtWidth = findViewById(R.id.edt_width);
Maksud dari baris diatas adalah objek edittext edtWidth disesuaikan (cast) dengan komponen edittext ber-id edt_width di layout xml melalui metode findViewById().
SetOnClickListener
- class MainActivity : AppCompatActivity(), View.OnClickListener {
- ...
- btnCalculate.setOnClickListener(this)
- ...
- override fun onClick(v: View) {
- ...
- }
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- ...
- btnCalculate.setOnClickListener(this);
- ...
- @Override
- public void onClick(View v) {
- ...
- }
Kita memasang event click listener untuk objek btnCalculate sehingga sebuah aksi dapat dijalankan ketika objek tersebut diklik.
Keyword this merujuk pada objek Activity saat ini yang telah mengimplementasikan listener OnClickListener sebelumnya. Sehingga ketika btnCalculate diklik, maka fungsi onClick akan dipanggil dan melukakan proses yang ada di dalamnya.
Selain menggunakan implementation seperti di atas, Anda juga dapat mengimplementasikannya langsung seperti ini:
Selain menggunakan implementation seperti di atas, Anda juga dapat mengimplementasikannya langsung seperti ini:
- btnCalculate.setOnClickListener {
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- ...
- }
- btnCalculate.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
- ...
- }
- });
Dengan menggunakan cara ini Anda tak perlu membuat method onClick dan implement View.OnClickListener di awal kelas. Namun Anda langsung mengimplementasikannya di dalam setOnClickListener.
Mengambil value dari EditText
- val inputLength = edtLength.text.toString().trim()
- val inputWidth = edtWidth.text.toString().trim()
- val inputHeight = edtHeight.text.toString().trim()
- String inputLength = edtLength.getText().toString().trim();
- String inputWidth = edtWidth.getText().toString().trim();
- String inputHeight = edtHeight.getText().toString().trim();
Sintaks .text.toString() di atas berfungsi untuk mengambil isi dari sebuah edittext kemudian menyimpannya dalam sebuah variabel. Tambahan .trim() berfungsi untuk menghiraukan spasi jika ada, sehingga nilai yang didapat hanya berupa angka.
Validasi input yang kosong
- var isEmptyFields = false
- var isInvalidDouble = false
- when {
- inputLength.isEmpty() -> {
- isEmptyFields = true
- edtLength.error = "Field ini tidak boleh kosong"
- }
- inputWidth.isEmpty() -> {
- isEmptyFields = true
- edtWidth.error = "Field ini tidak boleh kosong"
- }
- inputHeight.isEmpty() -> {
- isEmptyFields = true
- edtHeight.error = "Field ini tidak boleh kosong"
- }
- }
- boolean isEmptyFields = false;
- boolean isInvalidDouble = false;
- if (TextUtils.isEmpty(inputLength)) {
- isEmptyFields = true;
- edtLength.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputWidth)) {
- isEmptyFields = true;
- edtWidth.setError("Field ini tidak boleh kosong");
- }
- if (TextUtils.isEmpty(inputHeight)) {
- isEmptyFields = true;
- edtHeight.setError("Field ini tidak boleh kosong");
- }
Sintaks .isEmpty() berfungsi untuk mengecek apakah inputan dari edittext itu masih kosong. Jika iya, maka kita akan menampilkan pesan error dan mengganti variabel boolean isEmptyField menjadi true supaya bisa lanjut ke proses selanjutnya.
Menampilkan data ke EditText
- if (!isEmptyFields) {
- val volume = inputLength.toDouble() * inputWidth.toDouble() * inputHeight.toDouble()
- tvResult.text = volume.toString()
- }
- if (!isEmptyFields) {
- double volume = Double.valueOf(inputLength) * Double.valueOf(inputWidth) * Double.valueOf(inputHeight);
- tvResult.setText(String.valueOf(volume));
- }
Sintaks !isEmptyFields memiliki arti "jika semua inputan tidak kosong".
Jika kondisi tersebut terpenuhi maka langkah selanjutnya yaitu melakukan proses perhitungan, namun di sini kita tidak dapat langsung melakukan perhitungan.
Hal ini karena secara default input di edittext tipe datanya berupa String, maka kita perlu untuk merubah tipe datanya terlebih dahulu menjadi double.
Setelah selesai proses perhitungan, maka selanjutnya yaitu menampilkan hasil pada textview tvResult.
Di sini dapat dilihat bahwa kita perlu merubah datanya yang sebelumnya double menjadi string lagi, hal ini karena untuk menampilkan ke dalam textview harus menggunakan tipe data string.
Pembahasan saveInstanceState
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- outState.putString(STATE_RESULT, tvResult.text.toString())
- }
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString(STATE_RESULT, tvResult.getText().toString());
- }
Perhatikan metode onSaveInstanceState. Di dalam metode tersebut, hasil perhitungan yang ditampilkan pada tvResult dimasukkan pada bundle kemudian disimpan isinya.
Untuk menyimpan data di sini menggunakan konsep key-value, dengan STATE_RESULT sebagai key dan isi dari tvResult sebagai value.
Fungsi onSaveInstanceState akan dipanggil secara otomatis sebelum sebuah Activity hancur.
Di sini kita perlu menambahkan onSaveInstanceState karena ketika orientasi berubah, activity tersebut akan di-destroy dan memanggil fungsi onCreate lagi, sehingga kita perlu menyimpan nilai hasil perhitungan tersebut supaya data tetap terjaga dan tidak hilang ketika orientasi berubah.
- if (savedInstanceState != null) {
- val result = savedInstanceState.getString(STATE_RESULT) as String
- tvResult.text = result
- }
- if (savedInstanceState != null){
- String result = savedInstanceState.getString(STATE_RESULT);
- tvResult.setText(result);
- }
Pada onCreate inilah kita menggunakan nilai bundle yang telah kita simpan sebelumnya pada onSaveInstanceState. Nilai tersebut kita dapatkan dengan menggunakan key yang sama dengan saat menyimpan, yaitu STATE_RESULT. Kemudian kita isikan kembali pada tvResult.
Selamat! Anda telah berhasil membuat dan menjalankan latihan Android pertama di peranti atau emulator. Silakan lanjut ke codelab berikutnya.
Source code dapat Anda unduh di:
Pastikan untuk mengunduh Git terlebih dahulu. Cek tautan di bawah ini: