Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Safe Navigation - Custom List NavType

Hi I'm pretty new to Android and Jetpack Compose so bear with me.

I have a screen with posts and when I click on a post I want to navigate to a separate screen of that post only.

Post data class

@Serializable
data class Post(
    val id: Int,
    val imageUrl: String,
    val postedDate: String,
    // val likes: List<Like> <--- this doens't work
)

Like data class

@Serializable
data class Like(
    val user: User
)

In my MainActivity:

        setContent {
            AppTheme {
                val navController = rememberNavController()
                NavHost(navController = navController, startDestination = FeedScreen) {
                    composable<FeedScreen> {
                        FeedScreen(navController)
                    }
                    composable<Post> { backStackEntry ->
                        val post: Post = backStackEntry.toRoute()
                        PostScreen(post, onGoBack = { navController.popBackStack() })
                    }
                }
            }

And in my feed screen

...
        Column(
            ...
        ) {
            posts.forEach { p ->
                Post(post = p, onClickCard = {
                    navController.navigate(p)
                })
            }
        }

This seems to work pretty well but if I uncomment the likes attribute, the app fails at runtime with

java.lang.IllegalArgumentException: Cannot cast likes of type kotlin.collections.List to a NavType. Make sure to provide custom NavType for this argument.

I've been looking around on how to implement a custom NavType for my List but couldn't find anything. Is there a way to do this?

Since I'm pretty new I'm not sure if this is the way to do this either so I'd also appreciate if you could give me an alternative. Would it be better to just pass the id and retrieve the Post again from the Db/API?

like image 218
Link Avatar asked Feb 23 '26 04:02

Link


1 Answers

follow this article to create a custom nav type https://medium.com/mercadona-tech/type-safety-in-navigation-compose-23c03e3d74a5 remember to pass the map of nav type to the composable function and the navDeepLink parameter, here is an example

composable<Screen.Note>(
            typeMap = mapOf(typeOf<LinkedHashSet<LabelUi>>() to navTypeOf<LinkedHashSet<LabelUi>>()),
            deepLinks = listOf(
                navDeepLink<Screen.Note>(
                    basePath = DEFAULT_URI,
                    typeMap = mapOf(typeOf<LinkedHashSet<LabelUi>>() to navTypeOf<LinkedHashSet<LabelUi>>()),
                ),

            )

and here is the navTypeOf implementation:

inline fun <reified T> navTypeOf(
    isNullableAllowed: Boolean = false,
    json: Json = Json,
) = object : NavType<T>(isNullableAllowed = isNullableAllowed) {
    override fun get(bundle: Bundle, key: String): T? =
        bundle.getString(key)?.let(json::decodeFromString)

    override fun parseValue(value: String): T = json.decodeFromString(Uri.decode(value))

    override fun serializeAsValue(value: T): String = Uri.encode(json.encodeToString(value))

    override fun put(bundle: Bundle, key: String, value: T) =
        bundle.putString(key, json.encodeToString(value))

}

the reason why Uri is used here is mentioned here: https://www.youtube.com/watch?v=qBxaZ071N0c

Remember to pass the type map to the toRoute method

like image 171
ABADA S Avatar answered Feb 24 '26 16:02

ABADA S



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!