راهنما: مهاجرت به ناوبری ایمن از نوع در Compose و Navigation 2

این راهنما فرآیند جایگزینی مسیرهای مبتنی بر رشته با انواع کاتلین قابل سریال‌سازی را برای دستیابی به ایمنی در زمان کامپایل و از بین بردن خرابی‌های زمان اجرا ناشی از غلط‌های املایی یا انواع آرگومان نادرست، تشریح می‌کند.

پیش‌نیازها

قبل از شروع مهاجرت، بررسی کنید که پروژه شما الزامات زیر را برآورده می‌کند:

  1. نسخه ناوبری : به‌روزرسانی به ناوبری جت‌پک ۲.۸.۰ یا بالاتر
  2. افزونه سریال‌سازی کاتلین :
  3. افزونه را به libs.versions.toml اضافه کنید:
[libraries]
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }

[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
  • وابستگی‌ها را به build.gradle.kts سطح بالا و build.gradle.kts سطح ماژول خود اضافه کنید.

مرحله ۱: مقاصد خود را تعریف کنید

رشته‌های مسیر ثابت خود را با اشیاء و کلاس‌های @Serializable جایگزین کنید.

  • برای صفحات بدون آرگومان : از یک data object استفاده کنید
  • برای صفحاتی که آرگومان دارند : از یک data class استفاده کنید

قبل (مبتنی بر رشته):

const val ROUTE_HOME = "home"
const val ROUTE_PROFILE = "profile/{userId}"

بعد از (تایپ کنید safe):

import kotlinx.serialization.Serializable

@Serializable
object Home

@Serializable
data class Profile(val userId: String)

مرحله ۲: به‌روزرسانی پیکربندی NavHost

NavHost خود را به‌روزرسانی کنید تا از انواع ژنریک جدید در توابع composable و dialog استفاده کند.

قبل از:

NavHost(navController, startDestination = "home") {
    composable("home") { HomeScreen(...) }
    composable("profile/{userId}") { backStackEntry ->
        val userId = backStackEntry.arguments?.getString("userId")
        ProfileScreen(userId)
    }
}

بعد از:

NavHost(navController, startDestination = Home) {
    composable<Home> {
        HomeScreen(...)
    }
    composable<Profile> { backStackEntry ->
        // The library automatically handles argument extraction
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(profile.userId)
    }
}

مرحله ۳: پیاده‌سازی فراخوانی‌های ناوبری ایمن از نوع داده

فراخوانی‌های ناوبریِ درون‌یابی‌شده با رشته را با نمونه‌های کلاس جایگزین کنید.

قبل از:

navController.navigate("profile/user123")

بعد از:

navController.navigate(Profile(userId = "user123"))

مرحله ۴: دسترسی به آرگومان‌ها در ViewModelها

اگر از ViewModel استفاده می‌کنید، اکنون می‌توانید شیء مسیر را مستقیماً از SavedStateHandle استخراج کنید.

پیاده‌سازی:

class ProfileViewModel(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    // Automatically parses arguments into the Profile class
    private val profile = savedStateHandle.toRoute<Profile>()
    val userId = profile.userId
}

مرحله 5: (پیشرفته) مدیریت انواع سفارشی

اگر نیاز به ارسال کلاس‌های داده پیچیده (نه فقط مقادیر اولیه) دارید، باید یک NavType سفارشی تعریف کنید.

  1. ایجاد نوع سفارشی : ``kotlin val SearchFilterType = object: NavType (isNullableAllowed = false) { override fun get(bundle: Bundle, key: String): SearchFilter? = Json.decodeFromString(bundle.getString(key) ?: return null)
override fun parseValue(value: String): SearchFilter =
    Json.decodeFromString(Uri.decode(value))

override fun put(bundle: Bundle, key: String, value: SearchFilter) {
    bundle.putString(key, Json.encodeToString(value))
}

}



2. **Register it in the Graph**:
```kotlin
composable<Search>(
    typeMap = mapOf(typeOf<SearchFilter>() to SearchFilterType)
) { ... }

بهترین شیوه‌ها و نکات

  • سلسله مراتب مهر و موم شده : برای برنامه‌های بزرگ، مسیرهای خود را با استفاده از یک رابط یا کلاس مهر و موم شده گروه‌بندی کنید تا ساختار ناوبری سازماندهی شود.
  • نمونه‌های شیء : برای مسیرهای بدون پارامتر، همیشه object به جای class استفاده کنید تا از تخصیص‌های غیرضروری جلوگیری شود.
  • انواع تهی‌پذیر : API جدید از انواع تهی‌پذیر (برای مثال، data class Search(val query: String?) ) پشتیبانی می‌کند و مقادیر پیش‌فرض را به‌طور خودکار ارائه می‌دهد.
  • تست : از navController.currentBackStackEntry?.hasRoute<T>() برای بررسی مقصد فعلی به شیوه‌ای ایمن از نظر نوع داده در طول تست‌های رابط کاربری استفاده کنید.