I'm getting this error while passing a parcelable ...
# compose
s
I'm getting this error while passing a parcelable as argument in navigation:
Copy code
java.lang.UnsupportedOperationException: Parcelables don't support default values.
        at androidx.navigation.NavType$ParcelableType.parseValue(NavType.java:679)
        at androidx.navigation.NavType.parseAndPut(NavType.java:96)
        at androidx.navigation.NavDeepLink.parseArgument(NavDeepLink.java:306)
        at androidx.navigation.NavDeepLink.getMatchingArguments(NavDeepLink.java:260)
        at androidx.navigation.NavDestination.matchDeepLink(NavDestination.java:474)
        at androidx.navigation.NavGraph.matchDeepLink(NavGraph.java:79)
        at androidx.navigation.NavController.navigate(NavController.java:1025)
        at androidx.navigation.NavController.navigate(NavController.java:1008)
        at androidx.navigation.NavController.navigate(NavController.java:994)
        at androidx.navigation.compose.NavHostControllerKt.navigate(NavHostController.kt:100)
This is my code:
Copy code
composable(Routing.Root.Main.route) {
    Routing.Root.Main.Content(
        onChatClick = { user ->
            navController.navigate("${Routing.Root.Conversation.route}/${user}")
        }
    )
}

composable(
    "${Routing.Root.Conversation.route}/{user}",
    arguments = listOf(navArgument("user") { type = NavType.ParcelableType(User::class.java) })
) { backStackEntry ->
    backStackEntry.arguments?.getParcelable<User>("user")?.let { user ->
        Routing.Root.Conversation.Content(user = user)
    }
}
And this is the User class:
Copy code
@Parcelize
data class User(
    val name: Name,
    val picture: Picture
) : Parcelable

@Parcelize
data class Name(
    val first: String,
    val last: String,
    val title: String
) : Parcelable

@Parcelize
data class Picture(
    val large: String,
    val medium: String,
    val thumbnail: String
) : Parcelable
I know @Ian Lake suggested using IDs but I don't wanna bother with that right now for a sample app. How can I fix this?
a
Same issue
m
same here 🙂
i
It is not possible to pass Parcelables, that is correct. My previous statement on how you should be approaching routes is still the recommendation: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1603915310355400?thread_ts=1603915006.355200&amp;cid=CJLTWPH7S
s
Well than why does
NavType.ParcelableType
exist?
i
It predates Navigation Compose
s
Alright so any future plans to support Parcelables?
i
Not at the moment. I can paste the same link on what you should be doing again if you'd like 😛
s
Haha guess I gotta refactor some code. Thanks
c
"but I don't wanna bother with that right now for a sample app. How can I fix this?" I would just put the object in your App class, or some AAC ViewModel if it's a sample app. Then pass the id, or even save the id to the same larger scope (app class, or AAC ViewModel) if it's only a sample. 😄
👍 1
i
Super easy to write
interface Repository { fun getUser(name: String): User }
, create an implementation that returns fake data, and add that to your composable's parameters. You also get a free, testable layer you can continue to use when you have a real implementation 🙃
👍 2
m
ok that means we are forced to use some sort of repository or cache or something from where the destination can fetch the object given its ID, right?
i
That's been a best practice for what you should have been doing all along, yes
👍 3
j
Regarding the Repository I think it is not always a good solution. If you have a list with a lot of data that you only show on one screen, and you also show one item on another screen, you should not hold all that information in memory for the whole app. So you need to find a way to scope that repository to the two screens… which is work and maintenance
i
Note that Navigation already lets you scope ViewModels to a specific sub-graph of your app, automatically cleaning it up after all of those destinations are removed from the back stack: https://developer.android.com/guide/navigation/navigation-programmatic#share_ui-related_data_between_destinations_with_viewmodel - the upcoming alpha02 release makes it easier to declare these subgraphs
But I would strongly suggest you really take a look and figure out what your source of truth is, how you handle offline cases, caching, process death, etc. Do you really want to clear out results downloaded from a server immediately? Or is it that you want a TTL on your caching layer so that users get instant results if they come back and do the same query?
e.g., if you deep link into a detail screen (i.e., the list screen has never been loaded), where does that data come from?
j
It depends a lot on the usecase: sometimes I use caching on the data layer, sometimes I do have a global object that does the caching so that data is available, a couple times I’ve used the scoped viewModel, and other times I rely on passing the parcelized data. I’m just trying to go for the simplest solution that is good enough, and passing parcelized data is very simple when it is enough 🙂
Regarding the upcoming sub-graph viewModels, will you also support scoping non-viewmodels to the sub-graph? Currently I do use fragments and ViewModels, and I’ve used that feature. But with compose I would like to avoid using android viewModels and instead use viewModels that are platform agnostic. And if it is not going to be supported short-term, is there any way to extend navigation that allows doing it myself?
5
d
On the same question, passing arrays is also not supported yet? That is also giving the same exception. I was trying to pass an
IntArray
i
You can build your own custom type and define exactly how you want to parse/unparse your value: https://developer.android.com/guide/navigation/navigation-kotlin-dsl#custom-types
🙌 2