Komponen Navigation menyediakan bahasa khusus domain berbasis Kotlin, atau
DSL, yang mengandalkan type-safe Kotlin
builder
kami. API ini memungkinkan Anda menyusun grafik secara deklaratif di kode Kotlin,
daripada di dalam resource XML. Hal ini dapat berguna jika Anda ingin membangun
navigasi secara dinamis. Misalnya, aplikasi Anda bisa
mendownload dan meng-cache sebuah
konfigurasi navigasi dari layanan web eksternal,
lalu menggunakan konfigurasi tersebut
konfigurasi untuk membangun grafik navigasi secara dinamis dalam metode
Fungsi onCreate()
.
Dependensi
Untuk menggunakan DSL Kotlin dengan Fragment, tambahkan dependensi berikut ke atribut
File build.gradle
:
Groovy
dependencies { def nav_version = "2.8.0" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.0" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Membuat grafik
Berikut adalah contoh dasar berdasarkan class Sunflower
aplikasi. Untuk ini
misalnya, kita memiliki dua tujuan: home
dan plant_detail
. Tujuan home
ada saat pengguna pertama kali meluncurkan aplikasi. Tujuan ini menampilkan daftar tanaman dari taman pengguna. Saat pengguna memilih salah satu tanaman, aplikasi akan menavigasi ke tujuan plant_detail
.
Gambar 1 menunjukkan tujuan berikut beserta argumen yang diperlukan oleh tujuan plant_detail
dan tindakan to_plant_detail
yang digunakan aplikasi untuk menavigasi dari home
ke plant_detail
.
Menghosting Grafik Nav DSL Kotlin
Agar dapat membuat grafik navigasi aplikasi, Anda memerlukan tempat untuk menghosting
grafik. Contoh ini menggunakan fragmen sehingga menghosting grafik dalam
NavHostFragment
di dalam
FragmentContainerView
:
<!-- activity_garden.xml -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" />
</FrameLayout>
Perhatikan bahwa atribut app:navGraph
tidak ditetapkan dalam contoh ini. Grafik
tidak ditetapkan sebagai resource di
folder res/navigation
sehingga perlu ditetapkan sebagai bagian dari onCreate()
dalam aktivitas tersebut.
Dalam XML, sebuah tindakan menggabungkan ID tujuan dengan satu atau beberapa argumen. Namun, saat menggunakan DSL Navigasi, rute dapat berisi argumen sebagai bagian dari rute tersebut. Artinya, tidak ada konsep tindakan saat menggunakan DSL.
Langkah selanjutnya adalah menentukan rute yang akan Anda gunakan saat menentukan grafik.
Membuat rute untuk grafik
Grafik navigasi berbasis XML diuraikan sebagai bagian
dari proses build Android. Konstanta numerik dibuat untuk setiap id
yang ditentukan dalam grafik. ID statis yang dihasilkan waktu {i>build<i} ini bukan
tersedia ketika membuat grafik navigasi saat runtime sehingga DSL Navigasi
menggunakan serial yang dapat diserialisasi
jenis konten, bukan
pelanggan. Setiap rute direpresentasikan oleh jenis unik.
Saat menangani argumen, argumen ini dibangun ke dalam rute jenis data. Hal ini memungkinkan Anda memiliki keamanan jenis untuk argumen navigasi.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Membuat grafik dengan NavGraphBuilder DSL
Setelah menentukan rute, Anda dapat membuat grafik navigasi.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = Home
) {
fragment<HomeFragment, Home> {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment, PlantDetail> {
label = resources.getString(R.string.plant_detail_title)
}
}
Dalam contoh ini, dua tujuan fragmen didefinisikan menggunakan
fragment()
Fungsi pembangun DSL. Fungsi ini memerlukan dua jenis
argumen
kami.
Pertama, class Fragment
yang menyediakan UI untuk tujuan ini. Menyetel ini memiliki efek yang sama dengan
menyetel atribut android:name
pada tujuan fragmen yang ditentukan
menggunakan XML.
Kedua, rute. Ini harus berupa jenis yang dapat diserialisasi yang diperluas dari Any
. Ini
harus berisi argumen navigasi apa pun yang akan digunakan oleh tujuan ini,
dan jenisnya.
Fungsi tersebut juga menerima lambda opsional untuk konfigurasi tambahan, seperti sebagai label tujuan, serta fungsi builder tersemat untuk argumen dan deep link.
Menavigasi dengan grafik DSL Kotlin
Terakhir, Anda dapat bernavigasi dari home
ke plant_detail
menggunakan
NavController.navigate()
panggilan:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
Di PlantDetailFragment
, Anda bisa mendapatkan argumen navigasi dengan mendapatkan
saat ini
NavBackStackEntry
dan menelepon
toRoute
untuk mendapatkan instance rute.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Jika PlantDetailFragment
menggunakan ViewModel
, dapatkan instance rute menggunakan
SavedStateHandle.toRoute
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Bagian lainnya dalam panduan ini menjelaskan elemen grafik navigasi umum, tujuan, dan cara menggunakannya saat membuat grafik.
Tujuan
DSL Kotlin menyediakan dukungan bawaan untuk tiga jenis tujuan:
tujuan Fragment
, Activity
, dan NavGraph
, yang masing-masing memiliki
fungsi ekstensi inline yang tersedia untuk mem-build dan mengonfigurasi
tujuan.
Tujuan fragmen
Tujuan
fragment()
Fungsi DSL dapat diparameterisasi dengan class fragmen untuk UI dan
jenis rute yang digunakan untuk mengidentifikasi tujuan ini secara unik, diikuti oleh lambda
tempat Anda dapat memberikan konfigurasi tambahan sebagaimana
dijelaskan dalam Menavigasi
dengan grafik DSL Kotlin Anda.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Tujuan aktivitas
Tujuan
activity()
Fungsi DSL mengambil suatu parameter jenis untuk rute tetapi tidak diparameterisasi untuk
semua class aktivitas penerapan. Sebagai gantinya, Anda menyetel activityClass
opsional di
lambda akhir. Fleksibilitas ini memungkinkan Anda menentukan tujuan aktivitas untuk
aktivitas yang harus diluncurkan menggunakan parameter implisit
intent, di mana error
tidak mungkin diterapkan. Seperti tujuan fragmen, Anda juga dapat
mengonfigurasi label, argumen kustom, dan deep link.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Tujuan grafik navigasi
Tujuan
navigation()
Fungsi DSL dapat digunakan untuk membuat navigasi bertingkat
grafik. Fungsi ini mengambil jenis
untuk rute yang akan
ditetapkan ke grafik ini. Fungsi ini juga memerlukan dua argumen:
rute tujuan awal grafik, dan lambda untuk lebih lanjut
mengonfigurasi grafik. Elemen yang valid mencakup tujuan lainnya, argumen kustom
jenis, deep link, dan label deskriptif untuk
tujuan.
Label ini berguna untuk mengikat grafik navigasi ke komponen UI menggunakan
NavigationUI
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Mendukung tujuan kustom
Jika Anda menggunakan jenis tujuan baru
yang tidak secara langsung mendukung DSL Kotlin, Anda dapat menambahkan tujuan ini ke
DSL Kotlin Anda menggunakan
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
Sebagai alternatif, Anda juga dapat menggunakan operator unary plus untuk menambahkan tujuan yang baru dibuat langsung ke grafik:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Menyediakan argumen tujuan
Argumen tujuan dapat ditetapkan sebagai bagian dari class rute. Dapat berupa didefinisikan dengan cara yang sama seperti yang Anda lakukan untuk class Kotlin apa pun. Argumen yang diperlukan adalah didefinisikan sebagai jenis non-nullable dan argumen opsional ditentukan dengan default masing-masing.
Mekanisme pokok untuk merepresentasikan rute
dan argumennya adalah {i>string<i}
berbasis browser. Menggunakan string untuk rute model memungkinkan status navigasi disimpan dan
dipulihkan dari disk selama konfigurasi
perubahan dan proses yang dimulai oleh sistem
kematian. Karena alasan ini,
setiap argumen navigasi harus dapat diserialisasi, yaitu, argumen tersebut harus memiliki
yang mengonversi representasi nilai argumen dalam memori menjadi
String
.
Serialisasi Kotlin
plugin
secara otomatis menghasilkan metode serialisasi untuk dasar
saat metode
Anotasi @Serializable
ditambahkan ke objek.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Menyediakan jenis kustom
Untuk jenis argumen kustom, Anda harus menyediakan class NavType
kustom. Ini
memungkinkan Anda mengontrol dengan tepat cara jenis Anda diuraikan dari rute atau deep link.
Misalnya, rute yang digunakan untuk mendefinisikan layar penelusuran bisa berisi kelas yang mewakili parameter penelusuran:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
NavType
kustom dapat ditulis sebagai:
val SearchParametersType = object : NavType<SearchParameters>(
isNullableAllowed = false
) {
override fun put(bundle: Bundle, key: String, value: SearchParameters) {
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): SearchParameters {
return bundle.getParcelable(key) as SearchParameters
}
override fun serializeAsValue(value: SearchParameters): String {
// Serialized values must always be Uri encoded
return Uri.encode(Json.encodeToString(value))
}
override fun parseValue(value: String): SearchParameters {
// Navigation takes care of decoding the string
// before passing it to parseValue()
return Json.decodeFromString<SearchParameters>(value)
}
}
Jenis ini kemudian dapat digunakan di DSL Kotlin Anda seperti jenis lainnya:
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
Saat menavigasi ke tujuan, buat instance rute Anda:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Parameter ini dapat diperoleh dari rute di tujuan:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Deep link
Deep link dapat ditambahkan ke tujuan mana pun, seperti yang dapat dilakukan dengan grafik navigasi berbasis XML. Semua prosedur yang sama seperti yang dijelaskan dalam Membuat deep link untuk tujuan diterapkan ke proses pembuatan deep link menggunakan DSL Kotlin.
Saat membuat deep link implisit
namun, Anda tidak memiliki sumber daya navigasi XML yang dapat dianalisis untuk
<deepLink>
elemen. Oleh karena itu, Anda tidak dapat mengandalkan penempatan <nav-graph>
dalam file AndroidManifest.xml
Anda dan harus menambahkan intent
memfilter ke aktivitas Anda secara manual. Niat
yang Anda berikan harus cocok dengan jalur dasar, tindakan, dan jenis MIME
deep link aplikasi Anda.
Deep link ditambahkan ke tujuan dengan memanggil fungsi deepLink
di dalam
lambda tujuan. Model ini menerima rute sebagai tipe berparameter, dan
parameter basePath
untuk jalur dasar URL yang digunakan untuk deep link.
Anda juga dapat menambahkan tindakan dan {i>mimetype<i} menggunakan
deepLinkBuilder
lambda akhir.
Contoh berikut membuat URI deep link untuk tujuan Home
.
@Serializable data object Home
fragment<HomeFragment, Home>{
deepLink<Home>(basePath = "www.example.com/home"){
// Optionally, specify the action and/or mime type that this destination
// supports
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
}
Format URI
Format URI deep link secara otomatis dibuat dari kolom rute menggunakan aturan berikut:
- Parameter yang diperlukan ditambahkan sebagai parameter jalur (contoh:
/{id}
) - Parameter dengan nilai default (parameter opsional) ditambahkan sebagai query
parameter (contoh:
?name={name}
) - Koleksi ditambahkan sebagai parameter kueri (contoh:
?items={value1}&items={value2}
) - Urutan parameter sesuai dengan urutan kolom dalam rute
Misalnya, jenis rute berikut:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
memiliki format URI yang dihasilkan:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Tidak ada batasan jumlah deep link yang dapat Anda tambahkan. Setiap kali Anda memanggil
deepLink()
,
deep link baru akan ditambahkan ke daftar yang dikelola untuk tujuan tersebut.
Batasan
Plugin Safe Args tidak
kompatibel dengan DSL Kotlin, karena plugin tersebut mencari file resource XML untuk
menghasilkan class Directions
dan Arguments
.