https://kotlinlang.org logo
#compose
Title
# compose
s

Se7eN

10/30/2020, 10:23 AM
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

Alberto

10/30/2020, 10:36 AM
Same issue
m

Manuel Lorenzo

10/30/2020, 10:42 AM
same here 🙂
i

Ian Lake

10/30/2020, 3:26 PM
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

Se7eN

10/30/2020, 3:34 PM
Well than why does
NavType.ParcelableType
exist?
i

Ian Lake

10/30/2020, 3:41 PM
It predates Navigation Compose
s

Se7eN

10/30/2020, 3:42 PM
Alright so any future plans to support Parcelables?
i

Ian Lake

10/30/2020, 3:47 PM
Not at the moment. I can paste the same link on what you should be doing again if you'd like 😛
s

Se7eN

10/30/2020, 3:48 PM
Haha guess I gotta refactor some code. Thanks
c

Colton Idle

10/30/2020, 6:48 PM
"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

Ian Lake

10/30/2020, 7:59 PM
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

Manuel Lorenzo

10/31/2020, 2:21 PM
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

Ian Lake

10/31/2020, 3:18 PM
That's been a best practice for what you should have been doing all along, yes
👍 3
j

Jordi Saumell

11/09/2020, 10:40 PM
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

Ian Lake

11/09/2020, 10:47 PM
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

Jordi Saumell

11/10/2020, 7:49 PM
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

Dilraj Singh

11/26/2021, 6:28 PM
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

Ian Lake

11/27/2021, 2:07 AM
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