Di codelab Aktivitas dan Intent, Anda telah menambahkan intent di aplikasi Words untuk berpindah di antara dua aktivitas. Meskipun merupakan pola navigasi yang penting untuk diketahui, pola ini hanya merupakan bagian dari proses membuat antarmuka pengguna yang dinamis untuk aplikasi Anda. Banyak aplikasi Android tidak memerlukan aktivitas terpisah untuk setiap layar. Faktanya, banyak pola UI umum, seperti tab, ada dalam satu aktivitas dan menggunakan fragmen.
Fragmen adalah bagian UI yang dapat digunakan kembali; fragmen dapat digunakan kembali dan disematkan dalam satu atau beberapa aktivitas. Dalam screenshot di atas, mengetuk tab tidak akan memicu intent untuk menampilkan layar berikutnya. Sebaliknya, beralih tab hanya akan menukar fragmen sebelumnya dengan fragmen lain. Semua ini terjadi tanpa meluncurkan aktivitas lain.
Anda bahkan dapat menampilkan beberapa fragmen sekaligus di satu layar, seperti tata letak detail master untuk perangkat tablet. Pada contoh di bawah, UI navigasi di sebelah kiri dan konten di sebelah kanan masing-masing dapat ditampung dalam fragmen terpisah. Kedua fragmen tersebut ada secara bersamaan dalam aktivitas yang sama.
Seperti yang dapat Anda lihat, fragmen adalah bagian yang tidak terpisahkan dari pembuatan aplikasi berkualitas tinggi. Dalam codelab ini, Anda akan mempelajari dasar-dasar fragmen dan mengonversi aplikasi Words untuk menggunakannya. Anda juga akan mempelajari cara menggunakan komponen Navigasi Jetpack dan file resource baru yang disebut Grafik Navigasi untuk berpindah antar-fragmen dalam aktivitas host yang sama. Di akhir codelab ini, Anda akan memulai keterampilan mendasar untuk mengimplementasikan fragmen di aplikasi berikutnya.
Prasyarat
Sebelum menyelesaikan codelab ini, Anda harus mengetahui
- Cara menambahkan file XML resource dan file Kotlin ke project Android Studio.
- Cara kerja siklus proses aktivitas di level atas.
- Cara mengganti dan menerapkan metode di class yang sudah ada.
- Cara membuat instance class Kotlin, mengakses properti class, dan metode panggilan.
- Pemahaman dasar tentang nilai nullable dan non-nullable serta mengetahui cara menangani nilai null dengan aman.
Yang akan Anda pelajari
- Perbedaan daur proses fragmen dengan daur proses aktivitas.
- Cara mengonversi aktivitas yang ada ke fragmen.
- Cara menambahkan tujuan ke grafik navigasi, dan meneruskan data antar-fragmen saat menggunakan plugin Safe Arg.
Yang akan Anda buat
- Anda akan memodifikasi aplikasi Words untuk menggunakan satu atau beberapa aktivitas fragmen, serta berpindah antar-fragmen menggunakan Komponen Navigasi.
Yang Anda perlukan
- Komputer yang dilengkapi Android Studio.
- Kode solusi aplikasi Words dari codelab Aktivitas dan Intent
Dalam codelab ini, Anda akan melanjutkan aktivitas yang terakhir dilakukan dengan aplikasi Words di akhir codelab Aktivitas dan Intent. Jika Anda telah menyelesaikan codelab untuk aktivitas dan intent, Anda dapat menggunakan kode Anda sebagai titik awal. Atau, Anda dapat mendownload kode sampai ke titik ini dari GitHub.
Mendownload kode awal untuk codelab ini
Codelab ini menyediakan kode awal bagi Anda untuk memperluas dengan fitur yang diajarkan dalam codelab ini. Kode awal mungkin berisi kode yang tidak asing bagi Anda dari codelab sebelumnya. Kode ini mungkin juga berisi kode yang asing bagi Anda dan kode yang akan Anda pelajari dalam codelab berikutnya.
Jika Anda menggunakan kode awal dari GitHub, pastikan nama foldernya adalah android-basics-kotlin-words-app-activities
. 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 membuat dan menjalankan aplikasi. Pastikan aplikasi berfungsi seperti yang diharapkan.
- Cari file project di jendela fitur Project untuk melihat cara aplikasi diterapkan.
Fragmen hanyalah bagian yang dapat digunakan kembali dari antarmuka pengguna aplikasi Anda. Seperti aktivitas, fragmen memiliki siklus proses dan dapat merespons input pengguna. Fragmen selalu ditampung dalam hierarki tampilan aktivitas saat ditampilkan di layar. Dengan adanya penekanan pada kemampuan dan modularitas, beberapa fragmen bahkan bisa dihosting secara bersamaan oleh satu aktivitas. Setiap fragmen mengelola siklus proses terpisah.
Siklus proses fragmen
Seperti aktivitas, fragmen bisa diinisialisasi dan dihapus dari memori, dan seluruh keberadaannya, muncul, hilang, dan muncul kembali di layar. Selain itu, sama seperti aktivitas, fragmen memiliki siklus proses dengan beberapa keadaan, dan menyediakan beberapa metode yang bisa Anda ganti untuk merespons transisi antar-status. Siklus proses fragmen memiliki lima status yang diwakili oleh enum Lifecycle.State.
- DIINISIALISASI: Instance fragmen baru telah dibuat instance-nya.
- DIBUAT: Metode siklus proses fragmen pertama dipanggil. Selama status ini, tampilan yang terkait dengan fragmen juga dibuat.
- DIMULAI: Fragmen terlihat di layar, tetapi tidak memiliki "fokus", artinya fragmen tidak dapat merespons input pengguna.
- DILANJUTKAN: Fragmen terlihat dan memiliki fokus.
- DIHANCURKAN: Objek fragmen telah dinonaktifkan.
Juga mirip dengan aktivitas, class Fragment
menyediakan banyak metode yang dapat Anda ganti untuk merespons peristiwa siklus proses.
onCreate()
: Fragmen telah dibuat instance-nya dan berada dalam statusCREATED
. Namun, tampilan yang sesuai belum dibuat.onCreateView()
: Metode ini adalah tempat Anda meluaskan tata letak. Fragmen telah memasuki statusCREATED
.onViewCreated()
: Ini akan dipanggil setelah tampilan dibuat. Dalam metode ini, Anda biasanya akan mengikat tampilan tertentu ke properti dengan memanggilfindViewById()
.onStart()
: Fragmen telah memasuki statusSTARTED
.onResume()
: Fragmen telah memasuki statusRESUMED
dan sekarang memiliki fokus (dapat menanggapi input pengguna).onPause()
: Fragmen telah memasuki kembali statusSTARTED
. UI terlihat oleh penggunaonStop()
: Fragmen telah memasuki kembali statusCREATED
. Instance objek telah dibuat, tetapi tidak lagi ditampilkan di layar.onDestroyView()
: Dipanggil tepat sebelum fragmen memasuki statusDESTROYED
. Tampilan telah dihapus dari memori, tetapi objek fragmen masih ada.onDestroy()
: Fragmen memasuki statusDESTROYED
.
Diagram di bawah merangkum siklus proses fragmen dan transisi antar-status.
Status siklus proses dan metode callback cukup mirip dengan yang digunakan untuk aktivitas. Namun, perhatikan perbedaannya dengan metode onCreate()
. Dengan aktivitas, Anda akan menggunakan metode ini untuk mengembangkan layout dan mengikat tampilan. Namun, dalam siklus proses fragmen, onCreate()
dipanggil sebelum tampilan dibuat sehingga Anda tidak dapat meng-inflate tata letak di sini. Sebagai gantinya, Anda akan melakukannya di onCreateView()
. Kemudian, setelah tampilan dibuat, metode onViewCreated()
akan dipanggil dan kemudian Anda dapat mengikat properti ke tampilan tertentu.
Meskipun mungkin terdengar seperti teori semata, Anda sekarang mengetahui dasar-dasar cara kerja fragmen, serta perbedaan dan persamaan fragmen tersebut dengan aktivitas. Di sisa codelab ini, Anda akan menerapkan pengetahuan tersebut. Pertama, Anda akan memigrasikan aplikasi Words yang telah Anda kerjakan sebelumnya untuk menggunakan tata letak berbasis fragmen. Kemudian, Anda akan menerapkan navigasi antar-fragmen dalam satu aktivitas.
Seperti halnya aktivitas, setiap fragmen yang Anda tambahkan akan terdiri dari dua file, yaitu file XML untuk tata letak serta class Kotlin untuk menampilkan data dan menangani interaksi pengguna. Anda akan menambahkan fragmen untuk daftar surat dan daftar kata.
- Dengan memilih aplikasi di Project Navigator, tambahkan fragmen berikut (File > New > Fragment > Fragment (Blank)) dan file class serta tata letak harus dibuat untuk masing-masing.
- Untuk fragmen pertama, tetapkan Nama Fragmen ke
LetterListFragment
. Nama Tata Letak Fragmen harus diisi sebagaifragment_letter_list
.
- Untuk fragmen kedua, tetapkan Nama Fragmen ke
WordListFragment
. Nama Tata Letak Fragmen harus diisi sebagaifragment_word_list.xml
.
- Class Kotlin yang dihasilkan untuk kedua fragmen berisi banyak kode boilerplate yang umumnya digunakan saat mengimplementasikan fragmen. Namun, saat Anda mempelajari fragmen untuk pertama kalinya, lanjutkan dan hapus semuanya kecuali deklarasi class untuk
LetterListFragment
danWordListFragment
dari kedua file. Kami akan memandu Anda menerapkan fragmen dari awal sehingga Anda mengetahui cara kerja semua kode. Setelah menghapus kode boilerplate, file Kotlin harus terlihat seperti berikut.
LetterListFragment.kt
package com.example.wordsapp
import androidx.fragment.app.Fragment
class LetterListFragment : Fragment() {
}
WordListFragment.kt
package com.example.wordsapp
import androidx.fragment.app.Fragment
class WordListFragment : Fragment() {
}
- Salin konten
activity_main.xml
kefragment_letter_list.xml
dan isiactivity_detail.xml
kefragment_word_list.xml
. Updatetools:context
difragment_letter_list.xml
ke.LetterListFragment
dantools:context
difragment_word_list.xml
ke.WordListFragment
.
Setelah perubahan tersebut, file tata letak fragmen akan terlihat seperti berikut.
fragment_letter_list.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".WordListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp" />
</FrameLayout>
fragment_word_list.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".WordListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp"
tools:listitem="@layout/item_view" />
</FrameLayout>
Seperti halnya aktivitas, Anda harus meng-inflate tata letak dan mengikat tampilan individu. Ada beberapa perbedaan kecil ketika bekerja dengan daur proses fragmen. Kami akan memandu Anda melalui proses penyiapan LetterListFragment
, lalu Anda akan mendapatkan kesempatan untuk melakukan hal yang sama pada WordListFragment
.
Untuk mengimplementasikan view binding di LetterListFragment
, Anda harus mendapatkan referensi nullable terlebih dahulu ke FragmentLetterListBinding
. Class binding seperti ini dihasilkan oleh Android Studio untuk setiap file tata letak, saat properti viewBinding
diaktifkan di bagian buildFeatures
pada file build.gradle. Anda hanya perlu menetapkan properti di class fragmen untuk setiap tampilan di FragmentLetterListBinding
.
Jenisnya harus FragmentLetterListBinding?
dan juga harus memiliki nilai awal null
. Mengapa membuatnya nullable? Karena Anda tidak dapat meng-inflate tata letak sampai onCreateView()
dipanggil. Ada periode waktu di sela-sela saat instance LetterListFragment
dibuat (saat siklusnya dimulai dengan onCreate()
) dan saat properti ini benar-benar dapat digunakan. Selain itu, harus diingat bahwa tampilan fragmen dapat dibuat dan dihancurkan beberapa kali selama siklus proses fragmen. Untuk alasan ini, Anda juga harus menyetel ulang nilai dalam metode siklus proses yang lain, onDestroyView()
.
- Dalam
LetterListFragment.kt
, mulai dengan mendapatkan referensi keFragmentLetterListBinding
, dan beri nama referensi_binding
.
private var _binding: FragmentLetterListBinding? = null
Karena nullable, setiap kali Anda mengakses properti _binding
, (misalnya _binding?.someView
), Anda harus menyertakan ?
demi keamanan null. Namun, itu tidak berarti Anda harus membuang kode yang memiliki tanda tanya hanya karena satu nilai null. Jika yakin nilai tidak akan null saat mengaksesnya, Anda dapat menambahkan !!
ke nama jenisnya. Kemudian, Anda dapat mengaksesnya seperti properti lain tanpa operator ?
.
- Buat properti baru yang disebut binding (tanpa garis bawah) dan tetapkan sama dengan
_binding!!
.
private val binding get() = _binding!!
Di sini, get()
berarti properti ini bersifat "hanya-dapatkan". Itu berarti Anda bisa mendapatkan nilainya, tetapi setelah ditetapkan (seperti di sini), Anda tidak dapat menetapkannya ke lainnya.
- Untuk mengimplementasikan
onCreate()
, cukup panggilsetHasOptionsMenu()
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
- Ingat bahwa dengan fragmen, tata letak akan diperluas di
onCreateView()
. ImplementasikanonCreateView()
dengan meng-inflate tampilan, menyetel nilai_binding
, dan menampilkan tampilan root.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentLetterListBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
- Di bawah properti
binding
, buat properti untuk tampilan recycler.
private lateinit var recyclerView: RecyclerView
- Kemudian, tetapkan nilai properti
recyclerView
dionViewCreated()
, dan panggilchooseLayout()
seperti yang Anda lakukan diMainActivity
. Anda akan segera memindahkan metodechooseLayout()
keLetterListFragment
. Jadi, jangan khawatir jika terjadi error.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
recyclerView = binding.recyclerView
chooseLayout()
}
Perhatikan bagaimana class binding sudah membuat properti untuk recyclerView
, dan Anda tidak perlu memanggil findViewById()
untuk setiap tampilan.
- Terakhir, di
onDestroyView()
, setel ulang properti_binding
kenull
karena tampilan sudah tidak ada.
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
- Satu-satunya hal yang perlu diperhatikan ialah bahwa terdapat beberapa perbedaan kecil dalam metode
onCreateOptionsMenu()
saat menangani fragmen. Meskipun classActivity
memiliki properti global yang disebutmenuInflater
, Fragmen tidak memiliki properti ini. Sebaliknya, inflater menu akan diteruskan keonCreateOptionsMenu()
. Perhatikan juga bahwa metodeonCreateOptionsMenu()
yang digunakan dengan fragmen tidak memerlukan pernyataan pengembalian. Implementasikan metode seperti yang ditunjukkan ini:
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.layout_menu, menu)
val layoutButton = menu.findItem(R.id.action_switch_layout)
setIcon(layoutButton)
}
- Pindahkan kode lainnya untuk
chooseLayout()
,setIcon()
, danonOptionsItemSelected()
dariMainActivity
sebagaimana adanya. Satu-satunya perbedaan yang perlu diperhatikan adalah fragmen bukanlahContext
karena sifatnya yang tidak seperti aktivitas. Anda tidak dapat meneruskanthis
(merujuk ke objek fragmen) sebagai konteks pengelola tata letak. Namun, fragmen menyediakan properticontext
yang dapat Anda gunakan sebagai gantinya. Sisa kode serupa denganMainActivity
.
private fun chooseLayout() {
when (isLinearLayoutManager) {
true -> {
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = LetterAdapter()
}
false -> {
recyclerView.layoutManager = GridLayoutManager(context, 4)
recyclerView.adapter = LetterAdapter()
}
}
}
private fun setIcon(menuItem: MenuItem?) {
if (menuItem == null)
return
menuItem.icon =
if (isLinearLayoutManager)
ContextCompat.getDrawable(this.requireContext(), R.drawable.ic_grid_layout)
else ContextCompat.getDrawable(this.requireContext(), R.drawable.ic_linear_layout)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_switch_layout -> {
isLinearLayoutManager = !isLinearLayoutManager
chooseLayout()
setIcon(item)
return true
}
else -> super.onOptionsItemSelected(item)
}
}
- Terakhir, salin properti
isLinearLayoutManager
dariMainActivity
. Tempatkan tag ini di bawah deklarasi propertirecyclerView
.
private var isLinearLayoutManager = true
- Sekarang semua fungsi telah dipindahkan ke
LetterListFragment
, dan yang perlu dilakukan classMainActivity
adalah meng-inflate tata letak sehingga fragmen ditampilkan dalam tampilan. Lanjutkan dan hapus semuanya dariMainActivity
, kecualionCreate()
. Setelah perubahan tersebut,MainActivity
hanya diizinkan menampung berikut.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Giliran Anda
Ini untuk memigrasi MainActivity
ke LettersListFragment
. Cara memigrasikan DetailActivity
hampir sama. Lakukan langkah-langkah berikut untuk memigrasikan kode ke WordListFragment
.
- Salin objek pendamping dari
DetailActivity
keWordListFragment
. Pastikan referensi keSEARCH_PREFIX
diWordAdapter
diupdate menjadi referensiWordListFragment
. - Tambahkan variabel
_binding
. Variabel harus nullable dan memilikinull
sebagai nilai awalnya. - Tambahkan variabel hanya-dapatkan yang disebut binding setara ke variabel
_binding
. - Inflate tata letak di
onCreateView()
, tetapkan nilai_binding
dan tampilkan tampilan root. - Lakukan penyiapan yang tersisa di
onViewCreated()
: dapatkan referensi ke tampilan pendaur ulang, setel pengelola tata letak dan adaptor, dan tambahkan dekorasi itemnya. Anda harus mendapatkan letter dari intent. Fragmen tidak memiliki propertiintent
dan dilarang mengakses intent aktivitas induk. Untuk saat ini, Anda dapat merujuk keactivity.intent
(bukanintent
diDetailActivity
) untuk mendapatkan tambahan. - Setel ulang
_binding
ke null dionDestroyView
. - Hapus kode yang tersisa dari
DetailActivity
, dan biarkan metodeonCreate()
saja.
Coba lakukan sendiri langkah-langkah tersebut sebelum melanjutkan. Panduan mendetail tersedia di langkah berikutnya.
Kami harap Anda sudah mendapatkan kesempatan memigrasikan DetailActivity
ke WordListFragment
. Proses ini hampir sama dengan memigrasikan MainActivity
ke LetterListFragment
. Jika Anda terhenti di titik tertentu, langkah penyelesaiannya dirangkum di bawah ini.
- Pertama, salin objek pendamping ke
WordListFragment
.
companion object {
val LETTER = "letter"
val SEARCH_PREFIX = "https://www.google.com/search?q="
}
- Kemudian di
LetterAdapter
, dionClickListener()
tempat Anda menjalankan intent, Anda harus mengupdate panggilan keputExtra()
, yang akan menggantiDetailActivity.LETTER
denganWordListFragment.LETTER
.
intent.putExtra(WordListFragment.LETTER, holder.button.text.toString())
- Demikian pula, di
WordAdapter
, Anda harus mengupdateonClickListener()
tempat Anda menavigasi ke hasil penelusuran kata, yang menggantiDetailActivity.SEARCH_PREFIX
denganWordListFragment.SEARCH_PREFIX
.
val queryUrl: Uri = Uri.parse("${WordListFragment.SEARCH_PREFIX}${item}")
- Kembali ke
WordListFragment
, Anda menambahkan variabel binding jenisFragmentWordListBinding?
.
private var _binding: FragmentWordListBinding? = null
- Lalu, buat variabel hanya-dapatkan sehingga Anda dapat mereferensikan tampilan tanpa harus menggunakan
?
.
private val binding get() = _binding!!
- Selanjutnya, Anda akan meng-inflate tata letak yang menetapkan variabel
_binding
dan menampilkan tampilan root. Perlu diingat bahwa untuk fragmen, Anda melakukannya dionCreateView()
, bukanonCreate()
.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWordListBinding.inflate(inflater, container, false)
return binding.root
}
- Berikutnya, Anda akan mengimplementasikan
onViewCreated()
. Caranya hampir sama dengan mengonfigurasirecyclerView
dionCreateView()
diDetailActivity
. Akan tetapi, karena fragmen tidak memiliki akses langsung ke intent, Anda harus mereferensikannya denganactivity.intent
. Namun, Anda harus melakukannya dionCreateView()
, karena tidak ada jaminan bahwa aktivitas tersebut sudah ada di awal siklus proses.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val recyclerView = binding.recyclerView
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = WordAdapter(activity?.intent?.extras?.getString(LETTER).toString(), requireContext())
recyclerView.addItemDecoration(
DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
)
}
- Terakhir, Anda dapat menyetel ulang variabel
_binding
dionDestroyView()
.
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
- Setelah semua fungsi ini dipindahkan ke WordListFragment, Anda sekarang bisa menghapus kode dari DetailActivity. Metode onCreate(). tidak perlu dipindahkan.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Menghapus DetailActivity
Setelah berhasil memigrasikan fungsi DetailActivity
ke WordListFragment
, Anda tidak perlu lagi menggunakan DetailActivity
. Anda dapat melanjutkan dan menghapus DetailActivity.kt
dan activity_detail.xml
serta membuat perubahan kecil pada manifes.
- Pertama, hapus
DetailActivity.kt
- Pastikan opsi Safe Delete Tidak Dicentang, lalu klik Oke.
- Selanjutnya, hapus
activity_detail.xml
. Sekali lagi, pastikan opsi Safe Delete tidak dicentang.
- Terakhir, karena
DetailActivity
tidak ada lagi, hapus detail aktivitas berikut dariAndroidManifest.xml
.
<activity
android:name=".DetailActivity"
android:parentActivityName=".MainActivity" />
Setelah menghapus aktivitas detail, Anda akan mendapatkan dua fragmen (LetterListFragment dan WordListFragment) dan satu aktivitas (MainActivity). Di bagian berikutnya, Anda akan mempelajari komponen Navigasi Jetpack dan mengedit activity_main.xml
sehingga dapat ditampilkan dan dinavigasi antarfragmen, bukan menghosting tata letak statis.
Android Jetpack menyediakan komponen Navigasi untuk membantu Anda menangani implementasi setiap navigasi, sederhana atau kompleks, di aplikasi Anda. Komponen Navigasi memiliki tiga bagian penting yang akan Anda gunakan untuk mengimplementasikan navigasi di aplikasi Words.
- Grafik Navigasi: Grafik navigasi adalah file XML yang memberikan representasi visual untuk navigasi dalam aplikasi. File ini terdiri dari tujuan yang sesuai dengan aktivitas dan fragmen individual serta tindakan di antara keduanya yang dapat digunakan dalam kode untuk menavigasi dari satu tujuan ke tujuan lain. Sama seperti file tata letak, Android Studio menyediakan editor visual untuk menambahkan tujuan dan tindakan ke grafik navigasi.
NavHost
:NavHost
digunakan untuk menampilkan tujuan yang membentuk grafik navigasi dalam aktivitas. Saat Anda menavigasi antar-fragmen, tujuan yang ditampilkan diNavHost
akan diupdate. Anda akan menggunakan implementasi bawaan yang disebutNavHostFragment
, diMainActivity
.NavController
: ObjekNavController
memungkinkan Anda mengontrol navigasi antar-tujuan yang ditampilkan diNavHost
. Saat menggunakan intent, Anda harus memanggil startActivity untuk menavigasi ke layar baru. Dengan komponen Navigasi, Anda dapat memanggil metodenavigate()
NavController
untuk menukar fragmen yang ditampilkan.NavController
juga membantu Anda menangani berbagai tugas umum seperti merespons tombol "up" sistem untuk menavigasi kembali ke fragmen yang ditampilkan sebelumnya.
Dependensi Navigasi
- Pada file
build.gradle
di level project, di buildscript > ext, di bawahmaterial_version
tetapkannav_version
yang setara dengan2.3.1
.
buildscript {
ext {
appcompat_version = "1.2.0"
constraintlayout_version = "2.0.2"
core_ktx_version = "1.3.2"
kotlin_version = "1.3.72"
material_version = "1.2.1"
nav_version = "2.3.1"
}
...
}
- Pada file
build.gradle
di level aplikasi, tambahkan kode berikut ke grup dependensi.
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Plugin Safe Args
Saat pertama kali menerapkan navigasi di aplikasi Words, Anda menggunakan intent eksplisit di antara kedua aktivitas tersebut. Untuk meneruskan data di antara kedua aktivitas tersebut, Anda memanggil metode putExtra()
dengan memasukkan huruf yang telah dipilih.
Sebelum mulai menerapkan komponen Navigasi ke dalam aplikasi Words, Anda juga akan menambahkan Safe Arg—plugin Gradle yang akan membantu Anda mengetik dengan aman saat meneruskan data antara dua fragmen.
Lakukan langkah-langkah berikut untuk mengintegrasikan SafeArgs ke dalam project Anda.
- Pada file
build.gradle
level teratas, di buildscript > dependencies, tambahkan classpath berikut.
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
- Pada file
build.gradle
di level aplikasi, dalamplugins
di bagian atas, tambahkanandroidx.navigation.safeargs.kotlin
.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'androidx.navigation.safeargs.kotlin'
}
- Setelah mengedit file Gradle, Anda mungkin akan melihat banner kuning di bagian atas yang meminta Anda menyinkronkan project. Klik "Sync Now" dan tunggu satu atau dua menit sementara Gradle mengupdate dependensi project Anda untuk memperlihatkan perubahan.
Setelah sinkronisasi selesai, Anda siap melanjutkan ke langkah berikutnya untuk menambahkan grafik navigasi.
Setelah Anda memahami dasar-dasar fragmen dan siklus prosesnya, sekarang saatnya membuat semuanya menjadi sedikit lebih menarik. Langkah berikutnya adalah menggabungkan komponen Navigasi. Komponen navigasi hanya mengacu pada sekumpulan alat untuk mengimplementasi navigasi, khususnya antar-fragmen. Anda akan menggunakan editor visual baru untuk membantu mengimplementasikan navigasi antar-fragmen, yaitu Grafik Navigasi (atau disingkat NavGraph).
Apa itu Grafik Navigasi?
Grafik Navigasi (atau disingkat NavGraph) merupakan pemetaan virtual dari navigasi aplikasi Anda. Setiap layar, atau dalam hal ini adalah fragmen, menjadi "tujuan" yang memungkinkan untuk dinavigasi. NavGraph
dapat diwakili oleh file XML yang menunjukkan hubungan dari setiap tujuan satu sama lain.
Di balik layar, tindakan ini sebenarnya akan membuat instance baru dari class NavGraph
. Namun, tujuan dari grafik navigasi ditampilkan kepada pengguna oleh FragmentContainerView
. Anda hanya perlu membuat file XML dan menentukan tujuan yang memungkinkan. Selanjutnya, Anda dapat menggunakan kode yang dihasilkan untuk menavigasi antar-fragmen.
Menggunakan FragmentContainerView di MainActivity
Karena sekarang tata letak Anda terdapat di fragment_letter_list.xml
dan fragment_word_list.xml
, file activity_main.xml
tidak perlu lagi berisi tata letak untuk layar pertama di aplikasi Anda. Sebagai gantinya, Anda akan menggunakan kembali MainActivity
untuk memuat FragmentContainerView
agar bertindak sebagai NavHost untuk fragmen Anda. Mulai saat ini, semua navigasi di aplikasi akan berlangsung dalam FragmentContainerView
.
- Ganti konten
FrameLayout
di activity_main.xml yang berupaandroidx.recyclerview.widget.RecyclerView
denganFragmentContainerView
. Beri IDnav_host_fragment
dan tetapkan tinggi dan lebar kematch_parent
untuk mengisi seluruh tata letak frame.
Ganti ini:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
...
android:padding="16dp" />
Dengan ini:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- Di bawah atribut id, tambahkan atribut
name
dan tetapkan keandroidx.navigation.fragment.NavHostFragment
. Anda dapat menentukan fragmen tertentu untuk atribut ini, tetapi menetapkannya keNavHostFragment
memungkinkanFragmentContainerView
untuk berpindah antar-fragmen.
android:name="androidx.navigation.fragment.NavHostFragment"
- Di bawah atribut layout_height dan layout_width, tambahkan atribut yang bernamaapp:navHost dan tetapkan ke
"true"
. Dengan demikian, penampung fragmen dapat berinteraksi dengan hierarki navigasi. Misalnya, jika tombol kembali sistem ditekan, penampung akan kembali ke fragmen yang telah ditampilkan sebelumnya, seperti yang terjadi saat aktivitas baru ditampilkan.
app:defaultNavHost="true"
- Tambahkan atribut
app:navGraph
dan tetapkan ke"@navigation/nav_graph"
. Ini akan mengarah ke file XML yang menentukan cara fragmen aplikasi Anda berpindah dari satu fragmen ke fragmen lain. Untuk saat ini, Android Studio akan menampilkan error simbol yang belum terselesaikan. Anda akan mengatasinya di tugas berikutnya.
app:navGraph="@navigation/nav_graph"
- Terakhir, karena Anda telah menambahkan dua atribut dengan namespace aplikasi, pastikan atribut xmlns:app ditambahkan ke
FrameLayout
.
<xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
Hanya ini perubahan dalam activity_main.xml. Selanjutnya, Anda akan membuat file nav_graph
.
Menyiapkan Grafik Navigasi
Tambahkan file grafik navigasi (File > New > Android Resource File), lalu isi kolom sebagai berikut:
- Nama File:
nav_graph.xml.
Ini sama dengan nama yang Anda tetapkan untuk atributapp:navGraph
. - Jenis Resource: Navigasi. Nama Direktori selanjutnya akan otomatis berubah menjadi navigasi. Folder resource baru yang disebut "navigasi" akan dibuat.
Setelah membuat file XML, Anda akan mendapatkan editor visual baru. Anda sudah mereferensikan nav_graph
di properti navGraph
FragmentContainerView
. Oleh karena itu, untuk menambahkan tujuan baru, klik tombol baru di kiri atas layar dan buat tujuan untuk setiap fragmen (satu untuk fragment_letter_list
dan satu untuk fragment_word_list
).
Setelah ditambahkan, fragmen ini akan muncul pada grafik navigasi di bagian tengah layar. Anda juga dapat memilih tujuan tertentu menggunakan hierarki komponen yang muncul di sebelah kiri.
Membuat tindakan navigasi
Untuk membuat tindakan navigasi antara letterListFragment
ke tujuan wordListFragment
, arahkan kursor mouse ke tujuan letterListFragment
dan tarik dari lingkaran yang muncul di sebelah kanan tujuan wordListFragment
.
Sekarang Anda seharusnya melihat tanda panah yang telah dibuat untuk mewakili tindakan di antara dua tujuan. Klik panah, dan Anda dapat melihat di panel atribut bahwa tindakan ini memiliki nama action_letterListFragment_to_wordListFragment
yang dapat dirujuk dalam kode.
Menentukan Argumen untuk WordListFragment
Saat menavigasi antar-aktivitas menggunakan intent, Anda dapat menentukan "tambahan" sehingga huruf yang dipilih dapat diteruskan ke wordListFragment
. Navigasi juga mendukung penerusan parameter antar-tujuan dan juga melakukannya dengan cara yang aman.
Pilih tujuan wordListFragment
dan pada panel atribut, di bawah Argumen, klik tombol tambah untuk membuat argumen baru.
Argumen harus berupa letter
dan jenisnya harus String
. Di sinilah plugin Safe Arg yang Anda tambahkan sebelumnya disertakan. Menetapkan argumen ini sebagai string akan memastikan String
akan diharapkan saat tindakan navigasi Anda dilakukan dalam kode.
Menetapkan Tujuan Awal
NavGraph Anda mengetahui semua tujuan yang diperlukan, tetapi bagaimana FragmentContainerView
mengetahui fragmen mana yang pertama ditampilkan? Di NavGraph, Anda perlu menetapkan daftar huruf sebagai tujuan awal.
Tetapkan tujuan awal dengan memilih letterListFragment
dan mengklik tombol Assign start destination.
Hanya itu yang perlu Anda lakukan dengan editor NavGraph. Pada tahap ini, lanjutkan dan buat projectnya. Project akan menghasilkan beberapa kode berdasarkan grafik navigasi agar Anda dapat menggunakan tindakan navigasi yang baru saja dibuat.
Melakukan Tindakan Navigasi
Buka LetterAdapter
.kt
untuk melakukan tindakan navigasi. IniProses ini hanya memerlukan dua langkah.
- Hapus konten
onClickListener()
dari tombol. Sebagai gantinya, Anda harus mengambil tindakan navigasi yang baru saja dibuat. Tambahkan kode berikut keonClickListener()
.
val action = LetterListFragmentDirections.actionLetterListFragmentToWordListFragment(letter = holder.button.text.toString())
Anda mungkin tidak mengenali beberapa nama class dan fungsi ini karena dibuat secara otomatis setelah Anda membuat project. Di sinilah plugin Safe Arg yang Anda tambahkan di langkah pertama muncul—tindakan yang dibuat di NavGraf diubah menjadi kode yang dapat Anda gunakan. Namun, nama harus cukup intuitif. LetterListFragmentDirections
memungkinkan Anda merujuk ke semua jalur navigasi yang mungkin dimulai dari letterListFragment
. Fungsi actionLetterListFragmentToWordListFragment()
adalah tindakan spesifik untuk menavigasi ke wordListFragment.
Setelah memiliki referensi ke tindakan navigasi, cukup dapatkan referensi ke NavController Anda (objek yang memungkinkan Anda melakukan tindakan navigasi) dan memanggil navigate()
yang meneruskan tindakan.
holder.view.findNavController().navigate(action)
Mengonfigurasi MainActivity
Bagian akhir penyiapan adalah MainActivity
. Hanya ada beberapa perubahan yang diperlukan di MainActivity
agar semuanya berfungsi.
- Buat properti
navController
. Properti ini ditandai sebagailateinit
karena akan dakan ditetapkan dalamonCreate
.
private lateinit var navController: NavController
- Kemudian, setelah panggilan ke
setContentView()
dionCreate()
, Anda harus mendapatkan referensi kenav_host_fragment
(ini adalah IDFragmentContainerView
Anda) dan menetapkan ke propertinavController
.
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
- Lalu di
onCreate()
, panggilsetupActionBarWithNavController()
dengan meneruskannavController
. Ini akan memastikan tombol panel tindakan (panel aplikasi), seperti opsi menu diLetterListFragment
terlihat.
setupActionBarWithNavController(navController)
- Terakhir, implementasikan
onSupportNavigateUp()
. Bersama dengan menetapkandefaultNavHost
ketrue
dalam XML, metode ini memungkinkan Anda menangani tombol up. Namun, aktivitas Anda harus menyediakan implementasi.
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
Di titik ini, semua komponen sudah siap untuk mendapatkan navigasi yang berfungsi dengan fragmen. Namun, setelah navigasi dilakukan menggunakan fragmen dan bukan dengan intent, intent tambahan untuk huruf yang Anda gunakan di WordListFragment
tidak akan berfungsi lagi. Pada langkah berikutnya, Anda akan mengupdate WordListFragment
, untuk mendapatkan argumen letter
.
Sebelumnya, Anda telah mereferensikan activity?.intent
di WordListFragment
untuk mengakses tambahan letter
. Meskipun cara ini berfungsi, ini bukanlah praktik terbaik karena fragmen dapat disematkan di tata letak lain dan di aplikasi yang lebih besar sehingga akan lebih sulit untuk mengasumsikan aktivitas mana yang termasuk dalam fragmen tersebut. Selain itu, jika navigasi dilakukan menggunakan nav_graph
dan argumen aman digunakan, intent tidak akan ada, sehingga mencoba mengakses intent tambahan tidak akan berhasil.
Untunglah, mengakses argumen yang aman cukup mudah, dan Anda tidak perlu menunggu hingga onViewCreated()
dipanggil.
- Di
WordListFragment
, buat propertiletterId
. Anda dapat menandainya sebagai lateinit agar tidak perlu membuatnya nullable.
private lateinit var letterId: String
- Kemudian ganti
onCreate()
(bukanonCreateView()
atauonViewCreated()
!) dan tambahkan hal berikut.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
letterId = it.getString(LETTER).toString()
}
}
Karena arguments
dapat bersifat opsional, pastikan Anda menghubungi let()
dan mengirimkan lambda. Kode ini akan dieksekusi dengan asumsi arguments
bukan null, dengan meneruskan argumen non-null untuk parameter it
. Namun, jika arguments
adalah null
, lambda tidak akan dieksekusi.
Meskipun bukan bagian dari kode aktual, Android Studio memberikan petunjuk yang berguna agar Anda mengetahui parameter it
.
Apa yang dimaksud dengan Bundle
? Anggap ini sebagai pasangan nilai kunci yang digunakan untuk meneruskan data antar-class, seperti aktivitas dan fragmen. Sebenarnya, Anda sudah menggunakan paket ketika memanggil intent?.extras?.getString()
saat menjalankan intent di versi pertama aplikasi ini. Caranya sama persis dengan cara mendapatkan string dari argumen saat menggunakan fragmen.
- Terakhir, Anda dapat mengakses
letterId
saat menetapkan adaptor tampilan pendaur ulang. Gantiactivity?.intent?.extras?.getString(LETTER).toString()
dionViewCreated()
denganletterId
.
recyclerView.adapter = WordAdapter(letterId, requireContext())
Anda berhasil! Luangkan waktu untuk menjalankan aplikasi. Sekarang aplikasi tersebut dapat berpindah di antara dua layar, tanpa intent, dan semuanya dalam satu aktivitas.
Anda berhasil mengonversi kedua layar untuk menggunakan fragmen. Sebelum perubahan dilakukan, panel aplikasi untuk setiap fragmen memiliki judul deskriptif untuk setiap aktivitas yang ada di panel aplikasi. Namun, setelah melakukan konversi untuk menggunakan fragmen, judul ini tidak lagi ada di aktivitas detail.
Fragmen memiliki properti yang disebut "label"
dan dapat digunakan untuk menetapkan judul sehingga aktivitas induk akan mengetahui cara penggunaanya dalam panel aplikasi.
- Di
strings.xml
, setelah nama aplikasi, tambahkan konstanta berikut.
<string name="word_list_fragment_label">Words That Start With {letter}</string>
- Anda dapat menetapkan label untuk setiap fragmen pada grafik navigasi. Kembali ke
nav_graph.xml
, lalu pilihletterListFragment
di hierarki komponen, dan di panel atribut, tetapkan label ke stringapp_name
- Pilih
wordListFragment
dan tetapkan label keword_list_fragment_label
Selamat atas pencapaian Anda sejauh ini! Jalankan aplikasi sekali lagi dan Anda akan melihat semuanya sama seperti di awal codelab. Semua navigasi Anda dihosting di satu aktivitas dengan fragmen yang terpisah untuk setiap layar. hanya untuk sekarang.
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 membuat dan menjalankan aplikasi. Pastikan aplikasi berfungsi seperti yang diharapkan.
- Cari file project di jendela fitur Project untuk melihat cara aplikasi diterapkan.
- Fragmen adalah bagian UI yang dapat digunakan kembali dan dapat disematkan dalam aktivitas.
- Siklus proses fragmen berbeda dengan siklus proses aktivitas karena menggunakan penyiapan tampilan yang terjadi di
onViewCreated()
, bukanonCreateView()
. FragmentContainerView
digunakan untuk menyematkan fragmen dalam aktivitas lain dan dapat mengelola navigasi antar-fragmen.
Menggunakan Komponen Navigasi
- Dengan menetapkan atribut
navGraph
dariFragmentContainerView
, Anda dapat menavigasi antar-fragmen dalam suatu aktivitas. - Editor
NavGraph
memungkinkan Anda menambahkan tindakan navigasi dan menentukan argumen antar-tujuan yang berbeda. - Menavigasi menggunakan intent mengharuskan Anda meneruskan tambahan, komponen Navigation menggunakan SafeArgs agar class dan metode untuk tindakan navigasi dapat dihasilkan secara otomatis guna, memastikan keamanan jenis dengan argumen.
Menggunakan kasus untuk fragmen.
- Dengan menggunakan komponen Navigasi, banyak aplikasi bisa mengelola seluruh tata letaknya dalam satu aktivitas dan semua navigasi terjadi antar-fragmen.
- Fragmen memungkinkan pola tata letak umum, seperti tata letak detail master di tablet, atau beberapa tab dalam aktivitas yang sama.