1. Sebelum memulai
Codelab ini memperkenalkan aplikasi baru bernama Lunch Tray yang akan Anda bangun sendiri. Codelab ini memandu Anda melakukan langkah-langkah untuk menyelesaikan project aplikasi Lunch Tray, seperti penyiapan dan pengujian project dalam Android Studio.
Codelab ini berbeda dari yang lain di kursus ini. Tidak seperti codelab sebelumnya, tujuan codelab ini bukan untuk menyediakan tutorial langkah demi langkah tentang cara membangun aplikasi. Codelab ini dimaksudkan untuk menyiapkan project yang akan Anda selesaikan secara independen, yang memberi Anda petunjuk cara menyelesaikan aplikasi dan memeriksa sendiri aplikasi Anda.
Kami menyediakan paket pengujian sebagai bagian dari aplikasi yang akan Anda download, bukan kode solusi. Anda akan menjalankan pengujian ini di Android Studio (kami akan menunjukkan cara melakukannya nanti dalam codelab ini) dan melihat apakah kode Anda lulus. Mungkin diperlukan beberapa kali percobaan—bahkan developer profesional jarang sekali lulus pengujian pada percobaan pertama. Setelah kode Anda lulus semua pengujian, Anda dapat menganggap project ini selesai.
Kami memahami bahwa Anda mungkin hanya ingin solusi untuk memeriksanya. Kami sengaja tidak menyediakan kode solusi karena ingin Anda mempraktikkan bagaimana rasanya menjadi developer profesional. Hal ini mungkin mengharuskan Anda menggunakan berbagai keterampilan yang belum Anda pelajari, seperti:
- Menelusuri Google untuk istilah-istilah, pesan error, dan bit kode dalam aplikasi yang tidak Anda kenali;
 - Menguji kode, membaca error, lalu melakukan perubahan pada kode dan mengujinya lagi;
 - Kembali ke konten sebelumnya di Dasar-Dasar Android untuk mengingat kembali apa yang telah Anda pelajari;
 - Membandingkan kode yang Anda ketahui berfungsi (yaitu, kode yang diberikan dalam project, atau kode solusi sebelumnya dari aplikasi lain dalam Unit 3) dengan kode yang Anda tulis.
 
Pada awalnya mungkin tampak sulit, tetapi kami 100 persen yakin Anda siap untuk project ini jika bisa menyelesaikan Unit 3. Jangan terburu-buru, dan jangan menyerah. Anda pasti bisa melakukannya.
Prasyarat
- Project ini ditujukan untuk pengguna yang telah menyelesaikan Unit 3 kursus Dasar-dasar Android di Kotlin.
 
Yang akan Anda bangun
- Anda akan mengambil aplikasi pemesanan makanan bernama Lunch Tray, menerapkan ViewModel dengan data binding, serta menambahkan navigasi antarfragmen.
 
Yang akan Anda butuhkan
- Komputer yang dilengkapi Android Studio.
 
2. Ringkasan aplikasi yang sudah selesai
Selamat datang di Project: Lunch Tray!
Seperti yang mungkin Anda ketahui, navigasi adalah bagian dasar dari pengembangan Android. Saat menggunakan aplikasi untuk mencari resep, menemukan rute ke restoran favorit, atau yang paling penting, memesan makanan, Anda tentu akan membuka-buka beberapa layar konten. Dalam project ini, Anda akan memanfaatkan keterampilan yang Anda pelajari di Unit 3 untuk membangun aplikasi pemesanan makan siang bernama Lunch Tray, yang menerapkan model tampilan, data binding, dan navigasi antar-layar.
Berikut adalah screenshot aplikasi final. Saat pertama kali meluncurkan aplikasi Lunch Tray, pengguna akan disambut dengan layar berisi satu tombol yang bertuliskan "Start Order".

Setelah mengklik Start Order, pengguna dapat memilih hidangan utama dari pilihan yang tersedia. Pengguna dapat mengubah pilihan mereka, yang memperbarui Subtotal yang ditampilkan di bagian bawah.

Layar berikutnya memungkinkan pengguna menambahkan makanan pendamping.

Setelah itu, layar akan memungkinkan pengguna memilih makanan tambahan untuk pesanannya.

Terakhir, pengguna melihat ringkasan biaya pesanan, yang dibagi menjadi subtotal, pajak penjualan, dan biaya total. Pengguna juga dapat mengirimkan atau membatalkan pesanan.

Kedua opsi tersebut mengembalikan pengguna ke layar pertama. Jika pengguna mengirimkan pesanannya, toast akan muncul di bagian bawah layar yang memberi tahu bahwa pesanan telah dikirim.

3. Memulai
Mendownload kode project
Perhatikan bahwa nama folder adalah android-basics-kotlin-lunch-tray-app. Pilih folder ini saat Anda membuka project di Android Studio.
- Buka halaman repositori GitHub yang disediakan untuk project.
 - Pastikan nama cabang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).
 

- Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.
 

- Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
 - Temukan file di komputer Anda (mungkin di folder Downloads).
 - Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.
 
Membuka project di Android Studio
- Mulai Android Studio.
 - Di jendela Welcome to Android Studio, klik Open.
 

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.

- Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
 - Klik dua kali pada folder project tersebut.
 - Tunggu Android Studio membuka project.
 - Klik tombol Run 
 untuk membangun dan menjalankan aplikasi. Pastikan aplikasi dibangun seperti yang diharapkan. 
Sebelum mulai menerapkan ViewModel dan navigasi, luangkan waktu untuk memastikan project akan berhasil dibuat dan Anda sudah memahami project tersebut. Saat menjalankan aplikasi untuk pertama kalinya, Anda akan melihat layar kosong. MainActivity tidak menampilkan fragmen apa pun, karena Anda belum menyiapkan grafik navigasi.
Struktur project harus mirip dengan project lain yang telah Anda gunakan. Paket terpisah disediakan untuk data, model, dan UI, serta direktori terpisah untuk resource.

Semua opsi makan siang yang dapat dipesan pengguna (hidangan utama, pendamping, dan tambahan) ditampilkan oleh class MenuItem dalam paket model. Objek MenuItem memiliki nama, deskripsi, harga, dan jenis.
data class MenuItem(
    val name: String,
    val description: String,
    val price: Double,
    val type: Int
) {
    fun getFormattedPrice(): String = NumberFormat.getCurrencyInstance().format(price)
}
Jenis ini ditampilkan oleh bilangan bulat yang berasal dari objek ItemType dalam paket konstan.
object ItemType {
    val ENTREE = 1
    val SIDE_DISH = 2
    val ACCOMPANIMENT = 3
}
Setiap objek MenuItem dapat ditemukan di DataSource.kt dalam paket data.
object DataSource {
    val menuItems = mapOf(
        "cauliflower" to
        MenuItem(
            name = "Cauliflower",
            description = "Whole cauliflower, brined, roasted, and deep fried",
            price = 7.00,
            type = ItemType.ENTREE
        ),
    ...
}
Objek ini hanya berisi peta yang terdiri dari kunci dan MenuItem yang sesuai. Anda akan mengakses DataSource dari ObjectViewModel, yang akan Anda terapkan terlebih dahulu.
Menentukan ViewModel
Seperti yang terlihat pada screenshot di halaman sebelumnya, aplikasi ini meminta tiga hal dari pengguna: hidangan utama, pendamping, dan tambahan. Layar ringkasan pesanan kemudian menampilkan subtotal dan menghitung pajak penjualan berdasarkan item yang dipilih, yang digunakan untuk menghitung total pesanan.
Dalam paket model, buka OrderViewModel.kt lalu Anda akan melihat beberapa variabel sudah ditetapkan. Properti menuItems hanya memungkinkan Anda mengakses DataSource dari ViewModel.
val menuItems = DataSource.menuItems
Pertama, ada juga beberapa variabel untuk previousEntreePrice, previousSidePrice, dan previousAccompanimentPrice. Karena subtotal diupdate saat pengguna membuat pilihannya (bukan ditambahkan di bagian akhir), variabel ini digunakan untuk melacak pilihan pengguna sebelumnya jika mereka mengubah pilihan sebelum beralih ke layar berikutnya. Anda akan menggunakannya untuk memastikan subtotal memperhitungkan perbedaan antara harga item sebelumnya dan yang dipilih saat ini.
private var previousEntreePrice = 0.0
private var previousSidePrice = 0.0
private var previousAccompanimentPrice = 0.0
Ada juga variabel pribadi, _entree, _side, dan _accompaniment, untuk menyimpan pilihan yang saat ini dipilih. Ini adalah jenis MutableLiveData<MenuItem?>. Masing-masing disertai dengan properti pendukung publik, entree, side, dan accompaniment, dari jenis yang tidak dapat diubah LiveData<MenuItem?>. Ini diakses oleh tata letak fragmen untuk menampilkan item yang dipilih di layar. MenuItem yang terdapat dalam objek LiveData juga nullable karena pengguna tidak dapat memilih hidangan utama, pendamping, dan/atau tambahan.
// Entree for the order
private val _entree = MutableLiveData<MenuItem?>()
val entree: LiveData<MenuItem?> = _entree
// Side for the order
private val _side = MutableLiveData<MenuItem?>()
val side: LiveData<MenuItem?> = _side
// Accompaniment for the order.
private val _accompaniment = MutableLiveData<MenuItem?>()
val accompaniment: LiveData<MenuItem?> = _accompaniment
Terdapat pula LiveData variabel untuk subtotal, total, dan pajak, yang menggunakan pemformatan angka sehingga ditampilkan sebagai mata uang.
// Subtotal for the order
private val _subtotal = MutableLiveData(0.0)
val subtotal: LiveData<String> = Transformations.map(_subtotal) {
    NumberFormat.getCurrencyInstance().format(it)
}
// Total cost of the order
private val _total = MutableLiveData(0.0)
val total: LiveData<String> = Transformations.map(_total) {
    NumberFormat.getCurrencyInstance().format(it)
}
// Tax for the order
private val _tax = MutableLiveData(0.0)
val tax: LiveData<String> = Transformations.map(_tax) {
    NumberFormat.getCurrencyInstance().format(it)
}
Terakhir, tarif pajak adalah nilai hardcode sebesar 0,08 (8%).
private val taxRate = 0.08
Ada enam metode di OrderViewModel yang perlu Anda terapkan.
setEntree(), setSide(), dan setAccompaniment()
Semua metode ini masing-masing harus berfungsi dengan cara yang sama untuk hidangan utama, pendamping, dan tambahan. Sebagai contoh, setEntree() harus melakukan hal berikut:
- Jika 
_entreebukannull(yaitu pengguna sudah memilih hidangan utama, tetapi mengubah pilihannya), setelpreviousEntreePriceke hargacurrent _entree. - Jika 
_subtotalbukannull, kurangi subtotal denganpreviousEntreePrice. - Perbarui nilai 
_entreeke hidangan utama yang diteruskan ke dalam fungsi (aksesMenuItemmenggunakanmenuItems). - Panggil 
updateSubtotal(), yang meneruskan harga hidangan utama yang baru dipilih. 
Logika untuk setSide() dan setAccompaniment() identik dengan implementasi untuk setEntree().
updateSubtotal()
updateSubtotal() dipanggil dengan argumen untuk harga baru yang harus ditambahkan ke subtotal. Metode ini harus melakukan tiga hal:
- Jika 
_subtotalbukannull, tambahkanitemPriceke_subtotal. - Sebaliknya, jika 
_subtotaladalahnull, setel_subtotalkeitemPrice. - Setelah 
_subtotalditetapkan (atau diupdate), panggilcalculateTaxAndTotal()sehingga nilai tersebut diupdate untuk mencerminkan subtotal baru. 
calculateTaxAndTotal()
calculateTaxAndTotal() harus mengupdate variabel untuk pajak dan total berdasarkan subtotal. Implementasikan metode berikut:
- Setel 
_taxsama dengan tarif pajak dikalikan dengan subtotal. - Setel 
_totalsama dengan subtotal ditambah pajak. 
resetOrder()
resetOrder() akan dipanggil saat pengguna mengirimkan atau membatalkan pesanan. Anda ingin memastikan aplikasi tidak memiliki sisa data saat pengguna memulai pesanan baru.
Implementasikan resetOrder() dengan menetapkan semua variabel yang Anda ubah di OrderViewModel kembali ke nilai aslinya (baik 0,0 atau null).
Membuat variabel data binding
Implementasikan data binding di file tata letak. Buka file tata letak, dan tambahkan variabel data binding jenis OrderViewModel dan/atau class fragmen yang sesuai.
Anda harus menerapkan semua komentar TODO untuk menetapkan teks dan mengklik pemroses dalam empat file tata letak:
fragment_entree_menu.xmlfragment_side_menu.xmlfragment_accompaniment_menu.xmlfragment_checkout.xml
Setiap tugas tertentu dicantumkan dalam komentar TODO dalam file tata letak, tetapi langkah-langkahnya dirangkum di bawah ini.
- Di 
fragment_entree_menu.xml, di tag<data>, tambahkan variabel binding untukEntreeMenuFragment. Untuk setiap tombol pilihan, Anda harus menyetel hidangan utama diViewModelsaat dipilih. Teks subtotal pada tampilan teks harus diupdate. Anda juga harus menetapkan atributonClickuntukcancel_buttondannext_buttonmasing-masing untuk membatalkan pesanan atau membuka layar berikutnya. - Lakukan hal yang sama di 
fragment_side_menu.xml, dengan menambahkan variabel binding untukSideMenuFragment, kecuali untuk menyetel hidangan pendamping dalam model tampilan saat setiap tombol pilihan dipilih. Teks subtotal juga harus diperbarui dan Anda juga harus menyetel atributonClickuntuk tombol batal dan tombol berikutnya. - Lakukan hal yang sama sekali lagi, tetapi di 
fragment_accompaniment_menu.xml, kali ini dengan variabel binding untukAccompanimentMenuFragment, menetapkan hidangan tambahan saat setiap tombol pilihan dipilih. Sekali lagi, Anda juga harus menyetel atribut untuk teks subtotal, tombol batal, dan tombol berikutnya. - Di 
fragment_checkout.xml, Anda harus menambahkan tag<data>agar dapat menentukan variabel binding. Dalam tag<data>, tambahkan dua variabel binding, satu untukOrderViewModel, dan satu lagi untukCheckoutFragment. Pada tampilan teks, Anda harus menyetel nama dan harga hidangan utama, hidangan pendamping, dan hidangan tambahan yang dipilih dariOrderViewModel. Anda juga harus menetapkan subtotal, pajak, dan total dariOrderViewModel. Kemudian, tetapkanonClickAttributessaat pesanan dikirimkan, dan saat pesanan dibatalkan, dengan menggunakan fungsi yang sesuai dariCheckoutFragment. 
.
Menginisialisasi variabel data binding di fragmen
Lakukan inisialisasi variabel data binding dalam file fragmen yang terkait di dalam metode, onViewCreated().
EntreeMenuFragmentSideMenuFragmentAccompanimentMenuFragmentCheckoutFragment
Membuat grafik navigasi
Seperti yang Anda pelajari di Unit 3, grafik navigasi dihosting di FragmentContainerView, yang terdapat dalam aktivitas. Buka activity_main.xml dan ganti TODO dengan kode berikut untuk mendeklarasikan FragmentContainerView.
<androidx.fragment.app.FragmentContainerView
   android:id="@+id/nav_host_fragment"
   android:name="androidx.navigation.fragment.NavHostFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:defaultNavHost="true"
   app:navGraph="@navigation/mobile_navigation"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintLeft_toLeftOf="parent"
   app:layout_constraintRight_toRightOf="parent"
   app:layout_constraintTop_toTopOf="parent" />
Pada grafik navigasi, mobile_navigation.xml ditemukan dalam paket res.navigation.

Ini adalah grafik navigasi untuk aplikasi. Namun, file tersebut saat ini kosong. Tugas Anda adalah menambahkan tujuan ke grafik navigasi dan membuat model navigasi berikut di antara layar.
- Navigasi dari 
StartOrderFragmentkeEntreeMenuFragment - Navigasi dari 
EntreeMenuFragmentkeSideMenuFragment - Navigasi dari 
SideMenuFragmentkeAccompanimentMenuFragment - Navigasi dari 
AccompanimentMenuFragmentkeCheckoutFragment - Navigasi dari 
CheckoutFragmentkeStartOrderFragment - Navigasi dari 
EntreeMenuFragmentkeStartOrderFragment - Navigasi dari 
SideMenuFragmentkeStartOrderFragment - Navigasi dari 
AccompanimentMenuFragmentkeStartOrderFragment - Tujuan Awal harus 
StartOrderFragment 
Setelah menyetel grafik navigasi, Anda perlu melakukan navigasi di class fragmen. Implementasikan komentar TODO yang tersisa di fragmen, serta MainActivity.kt.
- Untuk metode 
goToNextScreen()diEntreeMenuFragment,SideMenuFragment, danAccompanimentMenuFragment, buka layar berikutnya di aplikasi. - Untuk metode 
cancelOrder()diEntreeMenuFragment,SideMenuFragment,AccompanimentMenuFragment, danCheckoutFragment, terlebih dahulu panggilresetOrder()padasharedViewModel, lalu bukaStartOrderFragment. - Di 
StartOrderFragment, implementasikansetOnClickListener()agar dapat menavigasi keEntreeMenuFragment. - Di 
CheckoutFragment, implementasikan metodesubmitOrder(). PanggilresetOrder()disharedViewModel, lalu bukaStartOrderFragment. - Terakhir, di 
MainActivity.kt, setelnavControllerkenavControllerdariNavHostFragment. 
4. Menguji aplikasi
Project Lunch Tray berisi target "androidTest" dengan beberapa kasus pengujian: MenuContentTests, NavigationTests, dan OrderFunctionalityTests.
Menjalankan pengujian
Untuk menjalankan pengujian, Anda dapat melakukan salah satu dari hal berikut:
Untuk satu kasus pengujian, buka class kasus pengujian dan klik panah hijau di sebelah kiri deklarasi class. Kemudian Anda dapat memilih opsi Run dari menu. Tindakan ini akan menjalankan semua pengujian dalam kasus pengujian.

Sering kali Anda hanya ingin menjalankan satu pengujian, misalnya, jika hanya ada satu pengujian yang gagal dan yang lainnya lulus pengujian. Anda dapat menjalankan satu pengujian seperti halnya seluruh kasus pengujian. Gunakan panah hijau dan pilih opsi Run.

Jika memiliki beberapa kasus pengujian, Anda juga dapat menjalankan seluruh rangkaian pengujian. Sama seperti menjalankan aplikasi, Anda dapat menemukan opsi ini pada menu Run.

Perhatikan bahwa Android Studio akan menetapkan secara default ke target terakhir yang Anda jalankan (aplikasi, target pengujian, dll.), jadi jika menu masih menampilkan Run > Run ‘app', Anda dapat menjalankan target pengujian, dengan memilih Run > Run.

Kemudian, pilih target pengujian dari menu pop-up.

5. Opsional: Berikan masukan Anda kepada kami
Kami ingin mendengar pendapat Anda tentang project ini. Ikuti survei singkat ini untuk memberikan masukan kepada kami - masukan Anda akan membantu memandu project mendatang dalam kursus ini.