Fragmen dan Komponen Navigasi

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.

586ff7b88b0d2455.png

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.

92f1ecb9aadb7797.png

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

  1. Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
  2. Di halaman GitHub project, klik tombol Code yang akan menampilkan dialog.

Eme2bJP46u-pMpnXVfm-bS2N2dlyq6c0jn1DtQYqBaml7TUhzXDWpYoDI0lGKi4xndE_uJw8sKfwfOZ1fC503xCVZrbh10JKJ4iEHdLDwFfdvnOheNxkokITW1LW6UZTncVJJUZ5Fw

  1. Di dialog, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
  2. Temukan file di komputer Anda (mungkin di folder Downloads).
  3. Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.

Membuka project di Android Studio

  1. Mulai Android Studio.
  2. Di jendela Welcome to Android Studio, klik Open an existing Android Studio project.

Tdjf5eS2nCikM9KdHgFaZNSbIUCzKXP6WfEaKVE2Oz1XIGZhgTJYlaNtXTHPFU1xC9pPiaD-XOPdIxVxwZAK8onA7eJyCXz2Km24B_8rpEVI_Po5qlcMNN8s4Tkt6kHEXdLQTDW7mg

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > New > Import Project.

PaMkVnfCxQqSNB1LxPpC6C6cuVCAc8jWNZCqy5tDVA6IO3NE2fqrfJ6p6ggGpk7jd27ybXaWU7rGNOFi6CvtMyHtWdhNzdAHmndzvEdwshF_SG24Le01z7925JsFa47qa-Q19t3RxQ

  1. Di dialog Import Project, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
  2. Klik dua kali pada folder project tersebut.
  3. Tunggu Android Studio membuka project.
  4. Klik tombol Run j7ptomO2PEQNe8jFt4nKCOw_Oc_Aucgf4l_La8fGLCMLy0t9RN9SkmBFGOFjkEzlX4ce2w2NWq4J30sDaxEe4MaSNuJPpMgHxnsRYoBtIV3-GUpYYcIvRJ2HrqR27XGuTS4F7lKCzg untuk membuat dan menjalankan aplikasi. Pastikan aplikasi berfungsi seperti yang diharapkan.
  5. 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 status CREATED. Namun, tampilan yang sesuai belum dibuat.
  • onCreateView(): Metode ini adalah tempat Anda meluaskan tata letak. Fragmen telah memasuki status CREATED.
  • onViewCreated(): Ini akan dipanggil setelah tampilan dibuat. Dalam metode ini, Anda biasanya akan mengikat tampilan tertentu ke properti dengan memanggil findViewById().
  • onStart(): Fragmen telah memasuki status STARTED.
  • onResume(): Fragmen telah memasuki status RESUMED dan sekarang memiliki fokus (dapat menanggapi input pengguna).
  • onPause(): Fragmen telah memasuki kembali status STARTED. UI terlihat oleh pengguna
  • onStop(): Fragmen telah memasuki kembali status CREATED. Instance objek telah dibuat, tetapi tidak lagi ditampilkan di layar.
  • onDestroyView(): Dipanggil tepat sebelum fragmen memasuki status DESTROYED. Tampilan telah dihapus dari memori, tetapi objek fragmen masih ada.
  • onDestroy(): Fragmen memasuki status DESTROYED.

Diagram di bawah merangkum siklus proses fragmen dan transisi antar-status.

74470aacefa170bd.png

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.

  1. 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 sebagai fragment_letter_list.

898650e4cd0b2486.png

  • Untuk fragmen kedua, tetapkan Nama Fragmen ke WordListFragment. Nama Tata Letak Fragmen harus diisi sebagai fragment_word_list.xml.

4f04fca641487da1.png

  1. 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 dan WordListFragment 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() {

}
  1. Salin konten activity_main.xml ke fragment_letter_list.xml dan isi activity_detail.xml ke fragment_word_list.xml. Update tools:context di fragment_letter_list.xml ke .LetterListFragment dan tools:context di fragment_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().

  1. Dalam LetterListFragment.kt, mulai dengan mendapatkan referensi ke FragmentLetterListBinding, 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 ?.

  1. 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.

  1. Untuk mengimplementasikan onCreate(), cukup panggil setHasOptionsMenu().
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setHasOptionsMenu(true)
}
  1. Ingat bahwa dengan fragmen, tata letak akan diperluas di onCreateView(). Implementasikan onCreateView() 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
}
  1. Di bawah properti binding, buat properti untuk tampilan recycler.
private lateinit var recyclerView: RecyclerView
  1. Kemudian, tetapkan nilai properti recyclerView di onViewCreated(), dan panggil chooseLayout() seperti yang Anda lakukan di MainActivity. Anda akan segera memindahkan metode chooseLayout() ke LetterListFragment. 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.

  1. Terakhir, di onDestroyView(), setel ulang properti _binding ke null karena tampilan sudah tidak ada.
override fun onDestroyView() {
   super.onDestroyView()
   _binding = null
}
  1. Satu-satunya hal yang perlu diperhatikan ialah bahwa terdapat beberapa perbedaan kecil dalam metode onCreateOptionsMenu() saat menangani fragmen. Meskipun class Activity memiliki properti global yang disebut menuInflater, Fragmen tidak memiliki properti ini. Sebaliknya, inflater menu akan diteruskan ke onCreateOptionsMenu(). Perhatikan juga bahwa metode onCreateOptionsMenu() 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)
}
  1. Pindahkan kode lainnya untuk chooseLayout(), setIcon(), dan onOptionsItemSelected() dari MainActivity sebagaimana adanya. Satu-satunya perbedaan yang perlu diperhatikan adalah fragmen bukanlah Context karena sifatnya yang tidak seperti aktivitas. Anda tidak dapat meneruskan this (merujuk ke objek fragmen) sebagai konteks pengelola tata letak. Namun, fragmen menyediakan properti context yang dapat Anda gunakan sebagai gantinya. Sisa kode serupa dengan MainActivity.
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)
   }
}
  1. Terakhir, salin properti isLinearLayoutManager dari MainActivity. Tempatkan tag ini di bawah deklarasi properti recyclerView.
private var isLinearLayoutManager = true
  1. Sekarang semua fungsi telah dipindahkan ke LetterListFragment, dan yang perlu dilakukan class MainActivity adalah meng-inflate tata letak sehingga fragmen ditampilkan dalam tampilan. Lanjutkan dan hapus semuanya dari MainActivity, kecuali onCreate(). 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.

  1. Salin objek pendamping dari DetailActivity ke WordListFragment. Pastikan referensi ke SEARCH_PREFIX di WordAdapter diupdate menjadi referensi WordListFragment.
  2. Tambahkan variabel _binding. Variabel harus nullable dan memiliki null sebagai nilai awalnya.
  3. Tambahkan variabel hanya-dapatkan yang disebut binding setara ke variabel _binding.
  4. Inflate tata letak di onCreateView(), tetapkan nilai _binding dan tampilkan tampilan root.
  5. 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 properti intent dan dilarang mengakses intent aktivitas induk. Untuk saat ini, Anda dapat merujuk ke activity.intent (bukan intent di DetailActivity) untuk mendapatkan tambahan.
  6. Setel ulang _binding ke null di onDestroyView.
  7. Hapus kode yang tersisa dari DetailActivity, dan biarkan metode onCreate() 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.

  1. Pertama, salin objek pendamping ke WordListFragment.
companion object {
   val LETTER = "letter"
   val SEARCH_PREFIX = "https://www.google.com/search?q="
}
  1. Kemudian di LetterAdapter, di onClickListener() tempat Anda menjalankan intent, Anda harus mengupdate panggilan ke putExtra(), yang akan mengganti DetailActivity.LETTER dengan WordListFragment.LETTER.
intent.putExtra(WordListFragment.LETTER, holder.button.text.toString())
  1. Demikian pula, di WordAdapter, Anda harus mengupdate onClickListener() tempat Anda menavigasi ke hasil penelusuran kata, yang mengganti DetailActivity.SEARCH_PREFIX dengan WordListFragment.SEARCH_PREFIX.
val queryUrl: Uri = Uri.parse("${WordListFragment.SEARCH_PREFIX}${item}")
  1. Kembali ke WordListFragment, Anda menambahkan variabel binding jenis FragmentWordListBinding?.
private var _binding: FragmentWordListBinding? = null
  1. Lalu, buat variabel hanya-dapatkan sehingga Anda dapat mereferensikan tampilan tanpa harus menggunakan ?.
private val binding get() = _binding!!
  1. Selanjutnya, Anda akan meng-inflate tata letak yang menetapkan variabel _binding dan menampilkan tampilan root. Perlu diingat bahwa untuk fragmen, Anda melakukannya di onCreateView(), bukan onCreate().
override fun onCreateView(
   inflater: LayoutInflater,
   container: ViewGroup?,
   savedInstanceState: Bundle?
): View? {
   _binding = FragmentWordListBinding.inflate(inflater, container, false)
   return binding.root
}
  1. Berikutnya, Anda akan mengimplementasikan onViewCreated(). Caranya hampir sama dengan mengonfigurasi recyclerView di onCreateView() di DetailActivity. Akan tetapi, karena fragmen tidak memiliki akses langsung ke intent, Anda harus mereferensikannya dengan activity.intent. Namun, Anda harus melakukannya di onCreateView(), 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)
   )
}
  1. Terakhir, Anda dapat menyetel ulang variabel _binding di onDestroyView().
override fun onDestroyView() {
   super.onDestroyView()
   _binding = null
}
  1. 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.

  1. Pertama, hapus DetailActivity.kt

dd3b0bcf3ec81c9.png

  1. Pastikan opsi Safe Delete Tidak Dicentang, lalu klik Oke.

f2f1ff137b0057a7.png

  1. Selanjutnya, hapus activity_detail.xml. Sekali lagi, pastikan opsi Safe Delete tidak dicentang.

6090c1d640433e07.png

  1. Terakhir, karena DetailActivity tidak ada lagi, hapus detail aktivitas berikut dari AndroidManifest.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 di NavHost akan diupdate. Anda akan menggunakan implementasi bawaan yang disebut NavHostFragment, di MainActivity.
  • NavController: Objek NavController memungkinkan Anda mengontrol navigasi antar-tujuan yang ditampilkan di NavHost. Saat menggunakan intent, Anda harus memanggil startActivity untuk menavigasi ke layar baru. Dengan komponen Navigasi, Anda dapat memanggil metode navigate() 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.
  1. Pada file build.gradle di level project, di buildscript > ext, di bawah material_version tetapkan nav_version yang setara dengan 2.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"
    }

    ...

}

  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.

  1. Pada file build.gradle level teratas, di buildscript > dependencies, tambahkan classpath berikut.
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
  1. Pada file build.gradle di level aplikasi, dalam plugins di bagian atas, tambahkan androidx.navigation.safeargs.kotlin.
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'androidx.navigation.safeargs.kotlin'
}
  1. 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.

854d44a6f7c4c080.png

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.

  1. Ganti konten FrameLayout di activity_main.xml yang berupa androidx.recyclerview.widget.RecyclerView dengan FragmentContainerView. Beri ID nav_host_fragment dan tetapkan tinggi dan lebar ke match_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" />
  1. Di bawah atribut id, tambahkan atribut name dan tetapkan ke androidx.navigation.fragment.NavHostFragment. Anda dapat menentukan fragmen tertentu untuk atribut ini, tetapi menetapkannya ke NavHostFragment memungkinkan FragmentContainerView untuk berpindah antar-fragmen.
android:name="androidx.navigation.fragment.NavHostFragment"
  1. 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"
  1. 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"
  1. 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 atribut app:navGraph.
  • Jenis Resource: Navigasi. Nama Direktori selanjutnya akan otomatis berubah menjadi navigasi. Folder resource baru yang disebut "navigasi" akan dibuat.

e26ed91764a5616e.png

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).

307d036fce790feb.gif

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.

c9477af5828a83f4.gif

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.

b6bc3eaacd14bf50.png

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.

99bb085e39dd7b4a.png

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.

  1. Hapus konten onClickListener() dari tombol. Sebagai gantinya, Anda harus mengambil tindakan navigasi yang baru saja dibuat. Tambahkan kode berikut ke onClickListener().
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.

  1. Buat properti navController. Properti ini ditandai sebagai lateinit karena akan dakan ditetapkan dalam onCreate.
private lateinit var navController: NavController
  1. Kemudian, setelah panggilan ke setContentView() di onCreate(), Anda harus mendapatkan referensi ke nav_host_fragment (ini adalah ID FragmentContainerView Anda) dan menetapkan ke properti navController.
val navHostFragment = supportFragmentManager
    .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
  1. Lalu di onCreate(), panggil setupActionBarWithNavController() dengan meneruskan navController. Ini akan memastikan tombol panel tindakan (panel aplikasi), seperti opsi menu di LetterListFragment terlihat.
setupActionBarWithNavController(navController)
  1. Terakhir, implementasikan onSupportNavigateUp(). Bersama dengan menetapkan defaultNavHost ke true 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.

  1. Di WordListFragment, buat properti letterId. Anda dapat menandainya sebagai lateinit agar tidak perlu membuatnya nullable.
private lateinit var letterId: String
  1. Kemudian ganti onCreate() (bukan onCreateView() atau onViewCreated()!) 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.

96a6a3253cea35b0.png

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.

  1. Terakhir, Anda dapat mengakses letterId saat menetapkan adaptor tampilan pendaur ulang. Ganti activity?.intent?.extras?.getString(LETTER).toString() di onViewCreated() dengan letterId.
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.

c385595994ba91b5.png

Fragmen memiliki properti yang disebut "label" dan dapat digunakan untuk menetapkan judul sehingga aktivitas induk akan mengetahui cara penggunaanya dalam panel aplikasi.

  1. Di strings.xml, setelah nama aplikasi, tambahkan konstanta berikut.
<string name="word_list_fragment_label">Words That Start With {letter}</string>
  1. Anda dapat menetapkan label untuk setiap fragmen pada grafik navigasi. Kembali ke nav_graph.xml, lalu pilih letterListFragment di hierarki komponen, dan di panel atribut, tetapkan label ke string app_name

4568d78c606999d.png

  1. Pilih wordListFragment dan tetapkan label ke word_list_fragment_label

7e7e55ea2dfb65bb.png

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

  1. Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
  2. Di halaman GitHub project, klik tombol Code yang akan menampilkan dialog.

Eme2bJP46u-pMpnXVfm-bS2N2dlyq6c0jn1DtQYqBaml7TUhzXDWpYoDI0lGKi4xndE_uJw8sKfwfOZ1fC503xCVZrbh10JKJ4iEHdLDwFfdvnOheNxkokITW1LW6UZTncVJJUZ5Fw

  1. Di dialog, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
  2. Temukan file di komputer Anda (mungkin di folder Downloads).
  3. Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.

Membuka project di Android Studio

  1. Mulai Android Studio.
  2. Di jendela Welcome to Android Studio, klik Open an existing Android Studio project.

Tdjf5eS2nCikM9KdHgFaZNSbIUCzKXP6WfEaKVE2Oz1XIGZhgTJYlaNtXTHPFU1xC9pPiaD-XOPdIxVxwZAK8onA7eJyCXz2Km24B_8rpEVI_Po5qlcMNN8s4Tkt6kHEXdLQTDW7mg

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > New > Import Project.

PaMkVnfCxQqSNB1LxPpC6C6cuVCAc8jWNZCqy5tDVA6IO3NE2fqrfJ6p6ggGpk7jd27ybXaWU7rGNOFi6CvtMyHtWdhNzdAHmndzvEdwshF_SG24Le01z7925JsFa47qa-Q19t3RxQ

  1. Di dialog Import Project, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
  2. Klik dua kali pada folder project tersebut.
  3. Tunggu Android Studio membuka project.
  4. Klik tombol Run j7ptomO2PEQNe8jFt4nKCOw_Oc_Aucgf4l_La8fGLCMLy0t9RN9SkmBFGOFjkEzlX4ce2w2NWq4J30sDaxEe4MaSNuJPpMgHxnsRYoBtIV3-GUpYYcIvRJ2HrqR27XGuTS4F7lKCzg untuk membuat dan menjalankan aplikasi. Pastikan aplikasi berfungsi seperti yang diharapkan.
  5. 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(), bukan onCreateView().
  • FragmentContainerView digunakan untuk menyematkan fragmen dalam aktivitas lain dan dapat mengelola navigasi antar-fragmen.

Menggunakan Komponen Navigasi

  • Dengan menetapkan atribut navGraph dari FragmentContainerView, 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.