1. Sebelum memulai
Dalam codelab ini, Anda akan menyelesaikan penerapan aplikasi Cupcake lainnya, yang Anda mulai di codelab sebelumnya. Aplikasi Cupcake memiliki beberapa layar dan menampilkan alur pesanan untuk cupcake. Aplikasi yang sudah selesai harus memungkinkan pengguna dapat menjalankannya untuk:
- Membuat pesanan cupcake
- Menggunakan tombol Atas atau Kembali untuk membuka langkah urutan pesanan sebelumnya
- Membatalkan pesanan
- Mengirim pesanan ke aplikasi lain seperti aplikasi email
Di sepanjang proses, Anda akan mempelajari cara Android menangani tugas dan data sebelumnya untuk aplikasi. Ini akan memungkinkan Anda untuk memanipulasi data sebelumnya dalam skenario seperti membatalkan pesanan, yang membawa pengguna kembali ke layar pertama aplikasi (bukan layar sebelumnya dari alur pesanan).
Prasyarat
- Dapat membuat dan menggunakan model tampilan bersama di seluruh fragmen dalam suatu aktivitas
- Telah terbiasa menggunakan komponen Navigasi Jetpack
- Telah menggunakan data binding dengan LiveData untuk menjaga UI tetap sinkron dengan model tampilan
- Dapat membuat intent untuk memulai aktivitas baru
Yang akan Anda pelajari
- Cara navigasi memengaruhi data sebelumnya dari aplikasi
- Cara menerapkan perilaku data sebelumnya yang khusus
Yang akan Anda build
- Aplikasi pemesanan cupcake yang memungkinkan pengguna mengirim pesanan ke aplikasi lain dan memungkinkan pembatalan pesanan
Yang Anda perlukan
- Komputer yang dilengkapi Android Studio.
- Kode untuk aplikasi Cupcake setelah menyelesaikan codelab sebelumnya
2. Ringkasan aplikasi awal
Codelab ini menggunakan aplikasi Cupcake dari codelab sebelumnya. Anda dapat menggunakan kode dari penyelesaian codelab sebelumnya atau mendownload kode awal dari GitHub.
Mendownload kode awal untuk codelab ini
Jika Anda mendownload kode awal dari GitHub, perhatikan bahwa nama folder project adalah android-basics-kotlin-cupcake-app-viewmodel
. Pilih folder ini saat Anda membuka project di Android Studio.
Untuk mendapatkan kode codelab ini dan membukanya di Android Studio, lakukan hal berikut.
Mendapatkan kode
- Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
- Di halaman GitHub project, klik tombol Code yang akan menampilkan dialog.
- Di dialog, 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 an existing Android Studio project.
Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > New > Import Project.
- Di dialog Import Project, 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.
- Cari file project di jendela alat Project untuk melihat cara aplikasi disiapkan.
Sekarang, jalankan aplikasi dan seharusnya akan terlihat seperti ini.
Dalam codelab ini, Anda akan menyelesaikan implementasi tombol Naik di aplikasi terlebih dahulu, sehingga mengetuknya akan membawa pengguna ke langkah sebelumnya dalam alur pesanan.
Selanjutnya, Anda akan menambahkan tombol Cancel sehingga pengguna dapat membatalkan pesanan jika mereka berubah pikiran selama proses pemesanan.
Anda kemudian akan memperluas aplikasi sehingga mengetuk Send Order to Another App akan membagikan pesanan ke aplikasi lain. Lalu, pesanan bisa saja dikirim ke toko cupcake melalui email.
Mari selami dan selesaikan aplikasi Cupcake!
3. Mengimplementasikan perilaku tombol Atas
Di aplikasi Cupcake, panel aplikasi menampilkan panah untuk kembali ke layar sebelumnya. Panah ini dikenal sebagai tombol Naik, dan telah Anda pelajari di codelab sebelumnya. Tombol Naik saat ini tidak melakukan apa pun, jadi perbaiki bug navigasi ini di aplikasi terlebih dahulu.
- Di
MainActivity
, Anda seharusnya sudah memiliki kode untuk menyiapkan panel aplikasi (juga dikenal sebagai panel tindakan) dengan pengontrol nav. JadikannavController
sebagai variabel class sehingga Anda dapat menggunakannya di metode lain.
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
}
- Dalam class yang sama, tambahkan kode untuk mengganti fungsi
onSupportNavigateUp()
. Kode ini akan memintanavController
menangani navigasi naik di aplikasi. Jika tidak, kembali ke implementasi superclass (dalamAppCompatActivity
) untuk menangani tombol Naik.
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
- Jalankan aplikasi. Tombol Naik kini seharusnya berfungsi dari
FlavorFragment
,PickupFragment
, danSummaryFragment
. Saat Anda menavigasi langkah sebelumnya dalam alur pesanan, fragmen akan menampilkan rasa dan tanggal pengambilan yang tepat dari model tampilan.
4. Mempelajari tugas dan data sebelumnya
Sekarang Anda akan memperkenalkan tombol Cancel dalam alur pesanan aplikasi. Membatalkan pesanan kapan saja dalam proses pesanan akan mengembalikan pengguna ke StartFragment
. Untuk menangani perilaku ini, Anda akan mempelajari tugas dan data sebelumnya di Android.
Tugas
Aktivitas di Android ada dalam tugas. Saat Anda membuka aplikasi untuk pertama kalinya dari ikon peluncur, Android akan membuat tugas baru dengan aktivitas utama Anda. Tugas adalah koleksi aktivitas yang berinteraksi dengan pengguna saat melakukan pekerjaan tertentu (misalnya memeriksa email, membuat pesanan kue, mengambil foto).
Aktivitas disusun dalam stack, yang dikenal sebagai data sebelumnya, tempat setiap aktivitas baru yang dikunjungi pengguna didorong ke data sebelumnya untuk tugas. Anda dapat menganggapnya sebagai tumpukan panekuk, yang membuat setiap panekuk baru ditambahkan di atas tumpukan. Aktivitas di bagian atas tumpukan adalah aktivitas saat ini yang berinteraksi dengan pengguna. Aktivitas di bawahnya pada tumpukan telah ditempatkan di latar belakang dan telah dihentikan.
Data sebelumnya berguna saat pengguna ingin menavigasi mundur. Android dapat menghapus aktivitas saat ini dari bagian atas stack, menghancurkannya, dan memulai aktivitas di bawahnya lagi. Ini dikenal sebagai memunculkan aktivitas dari tumpukan, dan membawa aktivitas sebelumnya ke latar depan untuk diajak berinteraksi oleh pengguna. Jika pengguna ingin kembali beberapa kali, Android akan terus memunculkan aktivitas di bagian teratas tumpukan hingga Anda mencapai bagian bawah tumpukan. Jika tidak ada lagi aktivitas dalam data sebelumnya, pengguna akan diarahkan kembali ke layar peluncur perangkat (atau ke aplikasi yang meluncurkannya).
Mari kita lihat versi aplikasi Words yang Anda implementasikan dengan 2 aktivitas: MainActivity
dan DetailActivity
.
Saat pertama kali Anda meluncurkan aplikasi, MainActivity
terbuka dan ditambahkan ke data sebelumnya dari tugas.
Saat Anda mengklik sebuah huruf, DetailActivity
akan diluncurkan dan didorong ke data sebelumnya. Ini berarti DetailActivity
telah dibuat, dimulai, dan dilanjutkan sehingga pengguna dapat berinteraksi dengannya. MainActivity
ditempatkan di latar belakang, dan ditampilkan dengan warna latar belakang abu-abu dalam diagram.
Jika Anda mengetuk tombol Kembali, DetailActivity
dikeluarkan dari data sebelumnya dan instance DetailActivity
akan dihancurkan dan selesai.
Kemudian, item berikutnya di bagian atas data sebelumnya (MainActivity
) dibawa ke latar depan.
Dengan cara yang sama seperti data sebelumnya dapat melacak aktivitas yang telah dibuka oleh pengguna, data sebelumnya juga dapat melacak tujuan fragmen yang telah dikunjungi pengguna dengan bantuan komponen Navigasi Jetpack.
Library Navigasi memungkinkan Anda memunculkan tujuan fragmen dari data sebelumnya setiap kali pengguna menekan tombol Kembali. Perilaku default ini tersedia secara cuma-cuma, tanpa Anda perlu menerapkannya. Anda hanya perlu menulis kode jika memerlukan perilaku data sebelumnya yang khusus, yang akan Anda lakukan untuk aplikasi Cupcake.
Perilaku default aplikasi Cupcake
Mari kita lihat cara kerja data sebelumnya di aplikasi Cupcake. Hanya ada satu aktivitas di aplikasi, tetapi ada beberapa tujuan fragmen yang dinavigasi oleh pengguna. Oleh karena itu, tombol Kembali diinginkan untuk kembali ke tujuan fragmen sebelumnya setiap kali diketuk.
Saat pertama kali membuka aplikasi, tujuan StartFragment
akan ditampilkan. Tujuan tersebut akan didorong ke atas tumpukan.
Setelah memilih jumlah cupcake yang akan dipesan, Anda akan diarahkan ke FlavorFragment
, yang didorong ke data sebelumnya.
Saat memilih rasa dan mengetuk Next, Anda akan diarahkan ke PickupFragment
, yang akan didorong ke data sebelumnya.
Dan terakhir, setelah Anda memilih tanggal pengambilan dan mengetuk Next, Anda akan diarahkan ke SummaryFragment
, yang akan ditambahkan ke bagian atas data sebelumnya.
Dari SummaryFragment
, misalnya Anda mengetuk tombol Kembali atau Naik. SummaryFragment
muncul dari tumpukan dan dihancurkan.
PickupFragment
kini berada di atas data sebelumnya dan ditampilkan kepada pengguna.
Ketuk tombol Kembali atau Atas lagi. PickupFragment
dikeluarkan dari tumpukan, lalu FlavorFragment
ditampilkan.
Ketuk tombol Kembali atau Atas lagi. FlavorFragment
muncul dari tumpukan, lalu StartFragment
ditampilkan.
Saat Anda menavigasi mundur ke langkah sebelumnya dalam alur pesanan, hanya satu tujuan yang muncul pada satu waktu. Namun di tugas berikutnya, Anda akan menambahkan fitur pembatalan pesanan ke aplikasi. Tindakan ini mungkin mengharuskan Anda memunculkan beberapa tujuan di data sebelumnya sekaligus untuk mengembalikan pengguna ke StartFragment
untuk memulai pesanan baru.
Mengubah data sebelumnya di aplikasi Cupcake
Ubah file class dan tata letak FlavorFragment
, PickupFragment
, dan SummaryFragment
untuk menawarkan tombol untuk membatalkan pesanan kepada pengguna.
Menambahkan tindakan navigasi
Pertama-tama, tambahkan tindakan navigasi ke grafik navigasi di aplikasi Anda, sehingga memungkinkan pengguna untuk kembali ke StartFragment
dari tujuan berikutnya.
- Buka Navigation Editor dengan membuka file res > navigation > nav_graph.xm dan memilih tampilan Design.
- Saat ini, ada tindakan dari
startFragment
keflavorFragment
, tindakan dariflavorFragment
kepickupFragment
, dan tindakan daripickupFragment
kesummaryFragment
. - Klik dan tarik untuk membuat tindakan navigasi baru dari
summaryFragment
kestartFragment
. Anda dapat melihat petunjuk ini jika ingin mengingat kembali cara menghubungkan tujuan di grafik navigasi. - Dari
pickupFragment
, klik dan tarik untuk membuat tindakan baru kestartFragment
. - Dari
flavorFragment
, klik dan tarik untuk membuat tindakan baru kestartFragment
. - Setelah selesai, grafik navigasi akan terlihat seperti berikut.
Dengan perubahan ini, pengguna dapat berpindah-pindah dari salah satu fragmen terbaru dalam alur pesanan untuk kembali ke awal alur pesanan. Sekarang Anda memerlukan kode yang benar-benar dapat diakses dengan tindakan tersebut. Tempat yang sesuai adalah saat tombol Cancel diketuk.
Menambahkan tombol Cancel ke tata letak
Pertama-tama, tambahkan tombol Cancel ke file tata letak untuk semua fragmen kecuali StartFragment
. Tidak perlu membatalkan pesanan jika Anda sudah berada di layar pertama alur pesanan.
- Buka file tata letak
fragment_flavor.xml
. - Gunakan tampilan Split untuk mengedit XML secara langsung dan melihat pratinjau secara berdampingan.
- Tambahkan tombol Cancel di antara tampilan teks subtotal dan tombol Next. Tetapkan ID resource
@+id/cancel_button
dengan teks untuk ditampilkan sebagai@string/cancel
.
Tombol harus diposisikan secara horizontal di samping tombol Next sehingga muncul sebagai baris tombol. Untuk batasan vertikal, batasi bagian atas tombol Cancel di bagian atas tombol Next. Untuk batasan horizontal, batasi awal tombol Cancel ke penampung induk, dan batasi tepinya hingga awal tombol Next.
Selain itu, atur tombol Cancel dengan tinggi wrap_content
dan lebar 0dp
, sehingga dapat membagi lebar layar dengan tombol lainnya secara sama. Perhatikan bahwa tombol tidak akan terlihat di panel Preview hingga langkah berikutnya.
...
<TextView
android:id="@+id/subtotal" ... />
<Button
android:id="@+id/cancel_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/cancel"
app:layout_constraintEnd_toStartOf="@id/next_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/next_button" />
<Button
android:id="@+id/next_button" ... />
...
- Pada
fragment_flavor.xml
, Anda juga perlu mengubah batasan awal tombol Next dariapp:layout_constraintStart_toStartOf="parent
" menjadiapp:layout_constraintStart_toEndOf="@id/cancel_button"
. Tambahkan juga margin akhir pada tombol Cancel sehingga ada spasi kosong di antara kedua tombol tersebut. Sekarang tombol Cancel akan muncul di panel Preview di Android Studio.
...
<Button
android:id="@+id/cancel_button"
android:layout_marginEnd="@dimen/side_margin" ... />
<Button
android:id="@+id/next_button"
app:layout_constraintStart_toEndOf="@id/cancel_button"... />
...
- Dalam hal gaya visual, terapkan gaya Material Outlined Button (dengan atribut
style="?attr/materialButtonOutlinedStyle"
) sehingga tombol Cancel tidak muncul secara mencolok dibandingkan dengan tombol Next, yang merupakan tindakan utama yang Anda inginkan agar menjadi fokus pengguna.
<Button
android:id="@+id/cancel_button"
style="?attr/materialButtonOutlinedStyle" ... />
Tombol dan peletakan posisi sekarang terlihat bagus!
- Dengan cara yang sama, tambahkan tombol Cancel ke file tata letak
fragment_pickup.xml
.
...
<TextView
android:id="@+id/subtotal" ... />
<Button
android:id="@+id/cancel_button"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/side_margin"
android:text="@string/cancel"
app:layout_constraintEnd_toStartOf="@id/next_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/next_button" />
<Button
android:id="@+id/next_button" ... />
...
- Perbarui juga batasan awal pada tombol Next. Kemudian, tombol Cancel akan muncul di pratinjau.
<Button
android:id="@+id/next_button"
app:layout_constraintStart_toEndOf="@id/cancel_button" ... />
- Terapkan perubahan yang serupa pada file
fragment_summary.xml
, meskipun tata letak untuk fragmen ini sedikit berbeda. Anda akan menambahkan tombol Cancel di bawah tombol Send di vertikal indukLinearLayout
dengan beberapa margin di antaranya.
...
<Button
android:id="@+id/send_button" ... />
<Button
android:id="@+id/cancel_button"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_between_elements"
android:text="@string/cancel" />
</LinearLayout>
- Jalankan dan uji aplikasi. Sekarang Anda akan melihat tombol Cancel muncul di tata letak untuk
FlavorFragment
,PickupFragment
, danSummaryFragment
. Namun, mengetuk tombol tersebut belum menyebabkan apa pun. Siapkan pemroses klik untuk tombol-tombol tersebut di langkah berikutnya.
Menambahkan pemroses klik tombol Cancel
Dalam setiap class fragmen (kecuali StartFragment
), tambahkan metode bantuan yang menangani saat tombol Cancel diklik.
- Tambahkan metode
cancelOrder()
ini keFlavorFragment
. Apabila ada opsi rasa, jika pengguna memutuskan untuk membatalkan urutannya, hapus model tampilan dengan memanggilsharedViewModel.resetOrder().
Lalu navigasikan kembali keStartFragment
menggunakan tindakan navigasi dengan IDR.id.action_flavorFragment_to_startFragment.
fun cancelOrder() {
sharedViewModel.resetOrder()
findNavController().navigate(R.id.action_flavorFragment_to_startFragment)
}
Jika melihat error yang terkait dengan ID resource tindakan, Anda mungkin perlu kembali ke file nav_graph.xml
untuk memverifikasi bahwa tindakan navigasi juga disebut dengan nama yang sama (action_flavorFragment_to_startFragment
).
- Gunakan binding pemroses untuk menyiapkan pemroses klik pada tombol Cancel di tata letak
fragment_flavor.xml
. Mengklik tombol ini akan mengaktifkan metodecancelOrder()
yang baru saja Anda buat di classFragmentFlavor
.
<Button
android:id="@+id/cancel_button"
android:onClick="@{() -> flavorFragment.cancelOrder()}" ... />
- Ulangi proses yang sama untuk
PickupFragment
. Menambahkan metodecancelOrder()
ke class fragmen, yang mereset pesanan dan menavigasi dariPickupFragment
keStartFragment
.
fun cancelOrder() {
sharedViewModel.resetOrder()
findNavController().navigate(R.id.action_pickupFragment_to_startFragment)
}
- Di
fragment_pickup.xml
, setel pemroses klik pada tombol Cancel untuk memanggil metodecancelOrder()
saat diklik.
<Button
android:id="@+id/cancel_button"
android:onClick="@{() -> pickupFragment.cancelOrder()}" ... />
- Tambahkan kode serupa untuk tombol Cancel pada
SummaryFragment
, yang membawa pengguna kembali keStartFragment
. Anda mungkin perlu mengimporandroidx.navigation.fragment.findNavController
jika tidak diimpor secara otomatis untuk Anda.
fun cancelOrder() {
sharedViewModel.resetOrder()
findNavController().navigate(R.id.action_summaryFragment_to_startFragment)
}
- Di
fragment_summary.xml
, panggil metodecancelOrder()
SummaryFragment
saat tombol Cancel diklik.
<Button
android:id="@+id/cancel_button"
android:onClick="@{() -> summaryFragment.cancelOrder()}" ... />
- Jalankan dan uji aplikasi untuk memverifikasi logika yang baru saja Anda tambahkan ke setiap fragmen. Saat membuat pesanan cupcake, ketuk tombol Cancel di
FlavorFragment
,PickupFragment
, atauSummaryFragment
akan mengembalikan Anda keStartFragment
. Saat membuat pesanan baru, Anda akan melihat bahwa informasi dari pesanan sebelumnya telah dihapus.
Ini sepertinya sudah berfungsi, tetapi sebenarnya ada bug dengan navigasi mundur, setelah Anda kembali ke StartFragment
. Ikuti beberapa langkah berikutnya untuk mereproduksi bug.
- Ikuti alur pesanan untuk membuat pesanan cupcake baru sampai Anda mencapai layar ringkasan. Misalnya, Anda dapat memesan 12 cupcake, rasa cokelat, dan memilih tanggal pengambilan berikutnya.
- Lalu ketuk Cancel. Anda harus kembali ke
StartFragment
. - Ini terlihat benar, tetapi jika Anda mengetuk tombol Kembali sistem, Anda akan kembali ke layar ringkasan pesanan dengan ringkasan pesanan untuk 0 cupcake dan tanpa rasa. Hal ini salah dan tidak boleh ditampilkan kepada pengguna.
Pengguna mungkin tidak ingin kembali melalui alur pesanan. Selain itu, semua data pesanan dalam model tampilan telah dihapus, sehingga informasi ini tidak berguna. Sebaliknya, mengetuk tombol Kembali dari StartFragment
akan menutup aplikasi Cupcake.
Mari kita lihat seperti apa data sebelumnya saat ini, dan cara memperbaiki bug. Saat Anda membuat pesanan melalui layar ringkasan pesanan, setiap tujuan akan didorong ke data sebelumnya.
Dari SummaryFragment
, Anda membatalkan pesanan. Saat Anda menavigasi melalui tindakan dari SummaryFragment
ke StartFragment
, Android menambahkan instance StartFragment
lain sebagai tujuan baru di data sebelumnya.
Itulah sebabnya saat Anda mengetuk tombol Kembali dari StartFragment
, aplikasi akan menampilkan SummaryFragment
lagi (dengan informasi pesanan kosong).
Untuk memperbaiki bug navigasi ini, pelajari tentang cara komponen Navigasi memungkinkan Anda mengeluarkan tujuan tambahan dari data sebelumnya saat bernavigasi menggunakan tindakan.
Memunculkan tujuan tambahan dari data sebelumnya
Tindakan navigasi: atribut popUpTo
Dengan menyertakan atribut app:popUpTo
pada tindakan navigasi dalam grafik navigasi, lebih dari satu tujuan dapat dimunculkan dari data sebelumnya hingga tujuan yang ditentukan tercapai. Jika Anda menentukan app:popUpTo="@id/startFragment"
, tujuan di data sebelumnya akan dikeluarkan hingga Anda mencapai StartFragment
, yang akan tetap berada dalam tumpukan.
Jika Anda menambahkan perubahan ini ke kode dan menjalankan aplikasi, Anda akan menemukan bahwa saat membatalkan pesanan, Anda akan kembali ke StartFragment
. Namun, saat ini, saat mengetuk tombol Kembali dari StartFragment
, Anda akan melihat StartFragment
lagi (bukan keluar dari aplikasi). Ini juga bukan perilaku yang diinginkan. Seperti yang disebutkan sebelumnya, karena Anda menavigasi ke StartFragment
, Android sebenarnya menambahkan StartFragment
sebagai tujuan baru di data sebelumnya, jadi sekarang Anda memiliki 2 instance StartFragment di data sebelumnya. Sehingga, Anda perlu mengetuk tombol Kembali dua kali untuk keluar dari aplikasi.
Tindakan navigasi: atribut popUpToInclusive
Untuk memperbaiki bug baru ini, minta semua tujuan dikeluarkan dari data sebelumnya hingga dan termasuk StartFragment
. Lakukan hal ini dengan menentukan app:popUpTo="@id/startFragment"
dan app:popUpToInclusive="true"
pada tindakan navigasi yang sesuai. Dengan begitu, Anda hanya akan memiliki satu instance baru StartFragment
di data sebelumnya. Lalu, mengetuk tombol Kembali sekali dari StartFragment
akan menutup aplikasi. Mari kita buat perubahan ini sekarang.
Mengubah tindakan navigasi
- Buka Navigation Editor dengan membuka file res > navigation > nav_graph.xml.
- Pilih tindakan dari
summaryFragment
kestartFragment
, sehingga akan disorot dengan warna biru. - Perluas Attributes di sebelah kanan (jika belum dibuka). Cari Pop Behavior dalam daftar atribut yang dapat Anda ubah.
- Dari opsi dropdown, tetapkan popUpTo menjadi
startFragment
. Ini berarti semua tujuan di data sebelumnya akan dimunculkan (dimulai dari atas tumpukan dan bergerak ke bawah), hinggastartFragment
.
- Kemudian klik kotak centang popUpToInclusive hingga kotak ini menunjukkan tanda centang dan label true. Hal ini menunjukkan bahwa Anda ingin memunculkan tujuan hingga dan mencakup instance
startFragment
yang sudah ada di data sebelumnya. Kemudian, Anda tidak akan memiliki dua instancestartFragment
di data sebelumnya.
- Ulangi perubahan ini untuk tindakan yang menghubungkan
pickupFragment
kestartFragment
.
- Ulangi untuk tindakan yang menghubungkan
flavorFragment
kestartFragment
. - Setelah selesai, pastikan Anda telah melakukan perubahan yang tepat pada aplikasi Anda dengan melihat tampilan Code file grafik navigasi.
<navigation
android:id="@+id/nav_graph" ...>
<fragment
android:id="@+id/startFragment" ...>
...
</fragment>
<fragment
android:id="@+id/flavorFragment" ...>
...
<action
android:id="@+id/action_flavorFragment_to_startFragment"
app:destination="@id/startFragment"
app:popUpTo="@id/startFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/pickupFragment" ...>
...
<action
android:id="@+id/action_pickupFragment_to_startFragment"
app:destination="@id/startFragment"
app:popUpTo="@id/startFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/summaryFragment" ...>
<action
android:id="@+id/action_summaryFragment_to_startFragment"
app:destination="@id/startFragment"
app:popUpTo="@id/startFragment"
app:popUpToInclusive="true" />
</fragment>
</navigation>
Perhatikan bahwa untuk masing-masing dari 3 tindakan (action_flavorFragment_to_startFragment
, action_pickupFragment_to_startFragment
, dan action_summaryFragment_to_startFragment
), harus ada atribut yang baru ditambahkan app:popUpTo="@id/startFragment"
dan app:popUpToInclusive="true"
.
- Sekarang, jalankan aplikasi. Periksa alur pesanan dan ketuk Cancel. Saat Anda kembali ke
StartFragment
, ketuk tombol Kembali (hanya sekali!) dan Anda seharusnya keluar dari aplikasi.
Sebagai ringkasan dari apa yang terjadi, saat Anda membatalkan pesanan dan menuju kembali ke layar pertama aplikasi, semua tujuan fragmen dalam data sebelumnya muncul dari tumpukan, termasuk instance pertama StartFragment
. Setelah menyelesaikan tindakan navigasi, StartFragment
ditambahkan sebagai tujuan baru di data sebelumnya. Mengetuk Kembali dari sana akan memunculkan StartFragment
dari tumpukan, tanpa meninggalkan fragmen lagi di data sebelumnya. Karena itu, Android menyelesaikan aktivitas dan pengguna keluar dari aplikasi.
Berikut adalah tampilan aplikasi:
5. Mengirim pesanan
Aplikasi ini tampak mengagumkan sejauh ini! Tapi ada satu bagian yang hilang. Saat Anda mengetuk tombol kirim pesanan di SummaryFragment
, pesan Toast
masih akan muncul.
Pengguna akan merasakan pengalaman yang lebih berguna jika pesanan dapat dikirim dari aplikasi. Manfaatkan hal-hal yang telah Anda pelajari di codelab sebelumnya tentang penggunaan intent implisit untuk berbagi informasi dari aplikasi Anda ke aplikasi lain. Dengan begitu, pengguna dapat berbagi informasi pesanan cupcake dengan aplikasi email di perangkat, sehingga pesanan dapat dikirim ke toko cupcake melalui email.
Untuk menerapkan fitur ini, lihat bagaimana subjek email dan isi email disusun dalam screenshot di atas.
Anda akan menggunakan string ini yang sudah ada dalam file strings.xml
.
<string name="new_cupcake_order">New Cupcake Order</string>
<string name="order_details">Quantity: %1$s cupcakes \n Flavor: %2$s \nPickup date: %3$s \n Total: %4$s \n\n Thank you!</string>
order_details
adalah resource string dengan 4 argumen format berbeda di dalamnya, yang merupakan placeholder untuk jumlah cupcake yang sebenarnya, rasa yang diinginkan, tanggal pengambilan yang diinginkan, dan harga total. Argumen diberi nomor dari 1 sampai 4 dengan sintaksis %1
sampai %4
. Jenis argumen juga ditentukan ($s
berarti string yang diharapkan ada di sini).
Dalam kode Kotlin, Anda dapat memanggil getString()
di R.string.order_details
diikuti dengan 4 argumen (urutan sifatnya penting!). Sebagai contoh, memanggil getString(R.string.order_details, "12", "Chocolate", "Sat Dec 12", "$24.00")
akan membuat string berikut, yang persis seperti isi email yang Anda inginkan.
Quantity: 12 cupcakes Flavor: Chocolate Pickup date: Sat Dec 12 Total: $24.00 Thank you!
- Dalam
SummaryFragment.kt
, ubah metodesendOrder()
. Hapus pesanToast
yang ada.
fun sendOrder() {
}
- Dalam metode
sendOrder()
, buat teks ringkasan pesanan. Buat stringorder_details
berformat dengan mendapatkan kuantitas, rasa, tanggal, dan harga pesanan dari model tampilan bersama.
val orderSummary = getString(
R.string.order_details,
sharedViewModel.quantity.value.toString(),
sharedViewModel.flavor.value.toString(),
sharedViewModel.date.value.toString(),
sharedViewModel.price.value.toString()
)
- Masih dalam metode
sendOrder()
, buat intent implisit untuk membagikan pesanan ke aplikasi lain. Lihat dokumentasi untuk mengetahui cara membuat intent email. TentukanIntent.ACTION_SEND
untuk tindakan intent, tetapkan jenis ke"text/plain"
dan sertakan tambahan intent untuk subjek email (Intent.EXTRA_SUBJECT
) dan isi email (Intent.EXTRA_TEXT
). Imporandroid.content.Intent
jika diperlukan.
val intent = Intent(Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.new_cupcake_order))
.putExtra(Intent.EXTRA_TEXT, orderSummary)
Sebagai tips bonus, jika Anda menyesuaikan aplikasi ini dengan kasus penggunaan Anda sendiri, Anda dapat mengisi penerima email terlebih dahulu sebagai alamat email toko cupcake. Dalam intent, Anda akan menentukan penerima email dengan intent tambahan Intent.EXTRA_EMAIL
.
- Karena ini adalah intent implisit, Anda tidak perlu mengetahui terlebih dahulu komponen atau aplikasi spesifik yang akan menangani intent ini. Pengguna akan memutuskan aplikasi mana yang ingin mereka gunakan untuk memenuhi intent tersebut. Namun, sebelum meluncurkan aktivitas dengan intent ini, periksa untuk melihat apakah ada aplikasi yang bahkan dapat menanganinya. Pemeriksaan ini akan mencegah aplikasi Cupcake menjadi error jika tidak ada aplikasi yang menangani intent tersebut, sehingga kode Anda menjadi lebih aman.
if (activity?.packageManager?.resolveActivity(intent, 0) != null) {
startActivity(intent)
}
Lakukan pemeriksaan ini dengan mengakses PackageManager
, yang berisi informasi tentang paket aplikasi yang diinstal di perangkat. PackageManager
dapat diakses melalui activity
fragmen, selama activity
dan packageManager
bukan null. Panggil metode resolveActivity()
PackageManager
dengan intent yang Anda buat. Jika hasilnya bukan null, maka aman untuk memanggil startActivity()
dengan intent Anda.
- Jalankan aplikasi Anda untuk menguji kode. Buat pesanan cupcake dan ketuk Send Order to Another App. Saat dialog berbagi muncul, Anda dapat memilih aplikasi Gmail, namun jangan ragu untuk memilih aplikasi lain jika mau. Jika memilih aplikasi Gmail, Anda mungkin perlu menyiapkan akun di perangkat jika belum melakukannya (misalnya, jika menggunakan emulator). Jika Anda tidak melihat pesanan cupcake terbaru muncul di isi email, Anda mungkin harus membuang draf email saat ini terlebih dahulu.
Dalam menguji skenario yang berbeda, Anda mungkin menemukan bug jika Anda hanya memiliki 1 cupcake. Ringkasan pesanan menyebutkan 1 cupcakes, namun ini salah secara tata bahasa dalam bahasa Inggris.
Sebagai gantinya, seharusnya tertulis 1 cupcake (bukan jamak). Jika Anda ingin memilih apakah kata cupcake atau cupcakes digunakan berdasarkan nilai kuantitas, Anda dapat menggunakan sesuatu yang disebut string kuantitas di Android. Dengan mendeklarasikan resource plurals
, Anda dapat menentukan resource string yang berbeda untuk digunakan berdasarkan berapa kuantitasnya, misalnya dalam kasus tunggal atau jamak.
- Tambahkan resource jamak
cupcakes
dalam filestrings.xml
Anda.
<plurals name="cupcakes">
<item quantity="one">%d cupcake</item>
<item quantity="other">%d cupcakes</item>
</plurals>
Dalam kasus tunggal (quantity="one"
), string tunggal akan digunakan. Dalam semua kasus lainnya (quantity="other"
), string jamak akan digunakan. Perhatikan bahwa sebagai ganti %s
yang mengharapkan argumen string, %d
mengharapkan argumen bilangan bulat, yang akan Anda teruskan saat memformat string.
Di kode Kotlin Anda, memanggil:
getQuantityString(R.plurals.cupcakes, 1, 1)
menampilkan string 1 cupcake
getQuantityString(R.plurals.cupcakes, 6, 6)
menampilkan string 6 cupcakes
getQuantityString(R.plurals.cupcakes, 0, 0)
menampilkan string 0 cupcakes
- Sebelum membuka kode Kotlin, perbarui resource string
order_details
distrings.xml
sehingga versi jamak dari cupcakes tidak lagi di-hardcode ke string tersebut.
<string name="order_details">Quantity: %1$s \n Flavor: %2$s \nPickup date: %3$s \n
Total: %4$s \n\n Thank you!</string>
- Di class
SummaryFragment
, perbarui metodesendOrder()
untuk menggunakan string kuantitas baru. Cara paling mudah adalah terlebih dahulu memahami kuantitas dari model tampilan dan menyimpannya dalam variabel. Karenaquantity
pada model tampilan adalah jenisLiveData<Int>
, bisa sajasharedViewModel.quantity.value
adalah null. Jika null, gunakan0
sebagai nilai default untuknumberOfCupcakes
.
Tambahkan ini sebagai baris kode pertama dalam metode sendOrder()
Anda.
val numberOfCupcakes = sharedViewModel.quantity.value ?: 0
Operator elvis (?:) berarti bahwa jika ekspresi di sebelah kiri bukan null, maka gunakanlah. Jika ekspresi di sebelah kiri adalah null, gunakan ekspresi di sebelah kanan operator elvis (yang dalam kasus ini adalah 0
).
- Lalu format string
order_details
seperti yang Anda lakukan sebelumnya. Alih-alih meneruskannumberOfCupcakes
sebagai argumen kuantitas secara langsung, buat string cupcake berformat denganresources.getQuantityString(R.plurals.cupcakes, numberOfCupcakes, numberOfCupcakes)
.
Metode sendOrder()
lengkap akan terlihat seperti berikut:
fun sendOrder() {
val numberOfCupcakes = sharedViewModel.quantity.value ?: 0
val orderSummary = getString(
R.string.order_details,
resources.getQuantityString(R.plurals.cupcakes, numberOfCupcakes, numberOfCupcakes),
sharedViewModel.flavor.value.toString(),
sharedViewModel.date.value.toString(),
sharedViewModel.price.value.toString()
)
val intent = Intent(Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.new_cupcake_order))
.putExtra(Intent.EXTRA_TEXT, orderSummary)
if (activity?.packageManager?.resolveActivity(intent, 0) != null) {
startActivity(intent)
}
}
- Jalankan dan uji kode Anda. Pastikan ringkasan pesanan di isi email menampilkan 1 cupcake vs. 6 cupcake atau 12 cupcake.
Dengan itu, Anda telah menyelesaikan semua fungsi aplikasi Cupcake! Selamat! Ini memang aplikasi yang menantang, dan Anda telah membuat kemajuan luar biasa dalam perjalanan Anda untuk menjadi developer Android! Anda telah berhasil menggabungkan semua konsep yang telah Anda pelajari sejauh ini, sambil mengambil beberapa tips mengatasi masalah baru selama proses ini.
Langkah terakhir
Sekarang luangkan waktu untuk membersihkan kode Anda, yang merupakan praktik coding yang baik yang telah Anda pelajari dari codelab sebelumnya.
- Mengoptimalkan impor
- Memformat ulang file
- Menghapus kode yang tidak digunakan atau dijadikan sebagai komentar
- Menambahkan komentar dalam kode jika diperlukan
Untuk membuat aplikasi lebih mudah diakses, uji aplikasi dengan Talkback yang diaktifkan untuk memastikan kelancaran pengalaman pengguna. Respons lisan harus membantu menyampaikan tujuan setiap elemen di layar, jika sesuai. Selain itu, pastikan bahwa semua elemen aplikasi dapat dinavigasi menggunakan gestur geser.
Periksa kembali bahwa semua kasus penggunaan yang diimplementasikan berfungsi seperti yang diharapkan dalam aplikasi final. Contoh:
- Data akan tetap dipertahankan meskipun terjadi rotasi perangkat (berkat model tampilan).
- Jika Anda mengetuk tombol Atas atau Kembali, informasi pesanan seharusnya tetap muncul dengan benar di
FlavorFragment
danPickupFragment
. - Mengirim pesanan ke aplikasi lain harus membagikan detail pesanan yang benar.
- Membatalkan pesanan akan menghapus semua informasi yang ada dalam pesanan.
Jika Anda menemukan bug, lanjutkan dan perbaiki bug tersebut.
Memeriksa ulang tugas Anda adalah perilaku yang cermat!
6. Kode solusi
Kode solusi untuk codelab ini ada dalam project yang ditampilkan di bawah.
Untuk mendapatkan kode codelab ini dan membukanya di Android Studio, lakukan hal berikut.
Mendapatkan kode
- Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
- Di halaman GitHub project, klik tombol Code yang akan menampilkan dialog.
- Di dialog, 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 an existing Android Studio project.
Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > New > Import Project.
- Di dialog Import Project, 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.
- Cari file project di jendela alat Project untuk melihat cara aplikasi disiapkan.
7. Ringkasan
- Android menyimpan data sebelumnya dari semua tujuan yang Anda kunjungi, dengan setiap tujuan baru dimasukkan ke tumpukan.
- Dengan mengetuk tombol Atas atau Kembali, Anda dapat mengeluarkan tujuan dari data sebelumnya.
- Menggunakan komponen Navigasi Jetpack membantu Anda mendorong dan memunculkan tujuan fragmen di data sebelumnya, sehingga perilaku tombol Kembali default tersedia secara cuma-cuma.
- Tentukan atribut
app:popUpTo
pada tindakan di grafik navigasi, untuk memunculkan tujuan di data sebelumnya hingga yang ditentukan dalam nilai atribut. - Tentukan
app:popUpToInclusive="true"
pada tindakan jika tujuan yang ditentukan dalamapp:popUpTo
juga akan dikeluarkan dari data sebelumnya. - Anda dapat membuat intent implisit untuk membagikan konten ke aplikasi email, menggunakan
Intent.ACTION_SEND
dan mengisi tambahan intent sepertiIntent.EXTRA_EMAIL
,Intent.EXTRA_SUBJECT
, danIntent.EXTRA_TEXT
. - Gunakan resource
plurals
jika Anda ingin menggunakan resource string yang berbeda berdasarkan kuantitas, seperti kasus tunggal atau jamak.
8. Mempelajari lebih lanjut
9. Berlatih sendiri
Perluas aplikasi Cupcake dengan variasi Anda sendiri pada alur pesanan cupcake. Contoh:
- Tawarkan rasa spesial yang disertai beberapa kondisi tertentu, seperti tidak tersedia untuk pengambilan pada hari yang sama.
- Minta nama pengguna untuk pesanan cupcake.
- Izinkan pengguna memilih beberapa rasa cupcake untuk pesanan mereka jika jumlahnya lebih dari 1 cupcake.
Area aplikasi mana yang perlu Anda perbarui untuk mengakomodasi fungsi baru ini?
Periksa hasil kerja Anda:
Aplikasi yang sudah selesai akan berjalan tanpa error.
10. Tugas Tantangan
Gunakan apa yang telah Anda pelajari dari mem-build aplikasi Cupcake guna mem-build aplikasi untuk kasus penggunaan Anda sendiri. Aplikasi ini dapat menjadi aplikasi untuk memesan pizza, roti isi, atau apa pun yang Anda inginkan! Sebaiknya Anda membuat sketsa berbagai tujuan aplikasi sebelum mulai menerapkannya.
Untuk mendapatkan inspirasi dari ide desain lain, Anda juga dapat melihat aplikasi Shrine yang merupakan studi Material yang menunjukkan cara menggunakan tema dan komponen Material untuk merek Anda sendiri. Aplikasi Shrine jauh lebih kompleks daripada aplikasi Cupcake yang telah Anda bangun. Sebaiknya pikirkan tentang fitur kecil yang dapat Anda tangani terlebih dahulu daripada bertujuan untuk membangun aplikasi yang sangat menantang di awal. Bangun kepercayaan diri Anda dari waktu ke waktu dengan keberhasilan yang bertahap.
Setelah selesai membuat aplikasi sendiri, bagikan hasil karya Anda ke media sosial. Gunakan hashtag #LearningKotlin agar kita dapat melihatnya!