Hi, i am trying to figure out how to do a compose ...
# compose
u
Hi, i am trying to figure out how to do a compose type-safe navigation subgraph with parameters right. Let’s say, I have a contact list screen. When a contact is clicked I want to start a
ContactDetailsFlow
consisting of two screens sharing a ViewModel with
ContactDetailsFlow
as the store owner.
Copy code
+- composable<ContactList>
|
+- navigation<ContactDetailsFlow>
   |
   +- composable<ContactDetailsScreen1>
   |
   +- composable<ContactDetailsScreen2>
Now the question is, • where to navigate to?
ContactDetailsFlow
or
ContactDetailsScreen1
? • who holds the parameter?
ContactDetailsFlow(id)
or `ContactDetailsScreen1(id)`/`ContactDetailsScreen2(id)`or all three? • If it is
ContactDetailsScreen1(id)
what would be the startDestination of
ContactDetailsFlow
? • If it is
ContactDetailsFlow(id)
how would deeplinks into the flow work (aka synthetic stack entry for
ContactDetailsFlow
)? • If it is
ContactDetailsFlow(id)
how would I navigate (not deeplink) straight to
ContactDetailsScreen2
Or maybe the question is simply, can I provide a factory to constuct
ContactDetailsFlow
’s route object from deeplinks/child routes during creation of the synthetic back stack. Or is there already any magic?
Or should I encapsulate the whole ContactDetailsFlow into it’s own NavHost and do any deeplinking by navigating to ContactDetailsFlow with a target parameter?
s
Would it work to have all the same params to both the graph and all individual destinations? That way you can deep link, and you can navigate to the individual screens. Btw, navigating to step2, without ever showing the startDestination of that graph does feel a bit suspect, are you sure these two need to be under a graph and not as standalone destinations on the root graph? Just curious.
u
> Would it work to have all the same params to both the graph and all individual destinations? Hi Stylianos, I can not figure out how that could work, that’s one of my problems. If ContactDetailsScreen1 needs an id, what would be the start destination of ContactDetailsFlow? And how would the synthetic back stack entry for ContactDetailsFlow get it’s id when deeplinking to ContactDetailsScreen1?
s
Hey Uli 🙂 What happens when you try that? What kind of crash do you experience, when you put the class itself as the start destination when both the graph and the destination have the same params, with the same name and arg position/types
u
I do not understand what you mean by “when you put the class itself as the start destination”. The start destination needs to be an instance of the route class.
s
I was thinking of this overload https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt;l=489?q=NavGraphBuilder.composable which takes in the start destination as a kclass instead of requiring an instance of it. But this could absolutely be wrong of course 😅
u
I don’t think so, but I’ll try out of desperation. For now I decided to just make it policy not to navigate into the nagiation node and give it an empty dummy start navigation.
Copy code
navigation<ContactDescriptionsFlowRoute>(
        startDestination = StartDestination,
    ) {
        composable<StartDestination> {
            // Unused. Only provided as dummy start destination
        }
        ...
s
I will say that this at least is for sure not a good thing to do. If you deep link somewhere in that graph and do navigateUp, this dummy destination will be added to the synthetic backstack.
u
I don’t think it will. The navigation node will be added to the back stack
s
What do you mean you don't think it will? I am talking about deep link scenarios, not if you just navigate to a node. In which case why even have the graph in the first place? You might just have all those destinations "inline" with the root graph so to speak.
u
Well, at least for the start destination, it looks like you are right and there is some voodoo going on, filling in the start destination parameters from the navigation node’s route. Thanks for that pointer, while I call it voodoo, it might be documented behaviour. Would you know about if and where that is documented?
In my experiment, I made the flow route + the two screen routes implement the same interface which brings in the parameter:
Copy code
@Serializable
private data class ContactDescriptionsFlowRoute(override val contactId: DbId) :
    ContactDescriptionsFlowParameters
And it works. not sure if the interface is required, but i think it states nicely, what i am doing.
s
Hehe, to be honest I don't know. It's just voodoo knowledge coming from trial and error. If you do find the right docs though please do link them to me too though, would be good to read what exactly are the guarantees we're getting here.
u
And just for the record, let me summarise the behaviour which comes in handy, but I call voodoo: • I set up the flow with a `startDestination`of
ContactDetails1Route::class
. Instances of which have a mandatory property
contactId
. • The flow itself has a route of
ContactDetailsFlowRoute(contactId)
• I navigate to
ContactDetailsFlowRoute(contactId)
. • Compose Navigation instantiates a route for the startDestination of type ContactDetails1Route (startDestination) with the contact id taken from th contactId property of it’s own route ContactDetailsFlowRoute. Notes: I am not sure how the contactId properties of
ContactDetailsFlowRoute
and
ContactDetails1Route
are linked. By name? By type? By position? (Both routes happen to be data classes and thereby have positional properties)
Thanks @Stylianos Gakis for pointing me in this direction. I would have never considered this by myself Dear android navigation team. A bit of information and discoverability in the docs would make this feature so much more valuable!
1
s
Perfect, thanks a lot for the recap on this! Would you mind filing a documentation issue about this? Probably with the exact same message as you wrote right here, and your use case. I would also like for this to be documented as clearly as possible. I would +1 that issue for sure!
101 Views