Rehber: Compose ve Navigation 2'de Tür Güvenli Gezinmeye Geçiş

Bu kılavuzda, derleme zamanında güvenlik sağlamak ve yazım hatalarından veya yanlış bağımsız değişken türlerinden kaynaklanan çalışma zamanı çökmelerini ortadan kaldırmak için dize tabanlı rotaları seri hale getirilebilir Kotlin türleriyle değiştirme süreci özetlenmektedir.

Ön koşullar

Taşıma işlemine başlamadan önce projenizin aşağıdaki koşulları karşıladığını doğrulayın:

  1. Navigation sürümü: Jetpack Navigation 2.8.0 veya daha yeni bir sürüme güncelleyin.
  2. Kotlin serialization plugin:
  3. Eklentiyi libs.versions.toml alanına ekleyin:
[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" }
  • Bağımlılıkları üst düzey build.gradle.kts ve modül düzeyindeki build.gradle.kts öğenize ekleyin.

1. adım: Hedeflerinizi tanımlayın

Sabit rota dizelerinizi @Serializable nesneleri ve sınıflarıyla değiştirin.

  • Bağımsız değişken içermeyen ekranlar için: data object kullanın.
  • Bağımsız değişken içeren ekranlar için: data class kullanın.

Önce (dize tabanlı):

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

Sonra (tür güvenli):

import kotlinx.serialization.Serializable

@Serializable
object Home

@Serializable
data class Profile(val userId: String)

2. adım: NavHost yapılandırmasını güncelleyin

composable ve dialog işlevinde yeni genel türleri kullanmak için NavHost öğenizi güncelleyin.

Önce:

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

Sonra:

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

3. adım: Tür güvenli gezinme çağrılarını uygulama

Dize enterpolasyonu yapılmış gezinme çağrılarını sınıf örnekleriyle değiştirin.

Önce:

navController.navigate("profile/user123")

Sonra:

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

4. adım: ViewModel'lerde bağımsız değişkenlere erişme

ViewModel kullanıyorsanız artık rota nesnesini doğrudan SavedStateHandle öğesinden çıkarabilirsiniz.

Uygulama:

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

5. adım: (Gelişmiş) Özel türleri işleme

Yalnızca temel veri türleri değil, karmaşık veri sınıfları da aktarmanız gerekiyorsa özel bir NavType tanımlamanız gerekir.

  1. Özel türü oluşturun: ```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)
) { ... }

En iyi uygulamalar ve ipuçları

  • Kapalı hiyerarşiler: Büyük uygulamalarda, gezinme yapısını düzenli tutmak için rotalarınızı kapalı bir arayüz veya sınıf kullanarak gruplandırın.
  • Nesne örnekleri: Parametresiz rotalarda gereksiz ayırmaları önlemek için class yerine her zaman object kullanın.
  • Boş Değer Atanabilir Türler: Yeni API, boş değer atanabilir türleri (ör. data class Search(val query: String?)) destekler ve varsayılan değerleri otomatik olarak sağlar.
  • Test etme: Kullanıcı arayüzü testleri sırasında mevcut hedefi tür güvenli bir şekilde kontrol etmek için navController.currentBackStackEntry?.hasRoute<T>() kullanın.