I don't know why I get NPE here while navigating t...
# compose
c
I don't know why I get NPE here while navigating to my screen. Anybody can help me out? https://stackoverflow.com/questions/74791657/how-can-i-navigation-to-other-screens-in-jetpack-compose
i
You're creating a brand new NavController that knows nothing about your `RootNavGraph`'s NavController when you call
rememberNavController()
inside your screen.
Why isn't your
AddSupplementItem
passed a lambda to handle click events? You show how to handle navigating correctly at the graph level for your authGraph
c
@Ian Lake So, Should I keep passing navcontroller from NavHost to that Screen?
Copy code
NavHost(...){
    // otherGraphs()
    supplementSearchScreen(navController)
}
something like this? I thought, It will catch it if I create in any Composable function.
i
no, that's the exact opposite thing from what you should be doing as explained in the guidance: https://developer.android.com/jetpack/compose/navigation#testing
As well as in the AndroidDevSummit talk:

https://www.youtube.com/watch?v=goFpG25uoc8

c
Well, I read them. But I didn't get it so I am asking here..
i
Here's what the first page says:
• Pass lambdas that should be triggered by the composable to navigate, rather than the
NavController
itself.
So your
AddSupplementItem
should take a
onItemClicked: () -> Unit
lambda, which then gets sent to whatever screen that composable is a part of (you don't show that part), which should also have a lambda parameter, all the way up the chain until it gets to your navigation graph and it is in that graph that you call
navController.navigateToSupplementSearch()
or whatever action you want
c
Hmm. the parent composable function is
Copy code
fun SupplementGrid(vitaminList: List<Vitamin>) {
     // list of vitamin item. and also use AddSupplement()
}
And also it has parent composable function
Copy code
@Composable
fun SupplementLayout(feedType: FeedType, supplements: List<Vitamin>) {
    // call SupplementGrid()
}
and finally,
Copy code
@Composable
fun NutritionScreen(
    // it uses LazyColumn and one of item is SupplementLayout()
)
So, should I call the
navController.navigateToSupplementSearch()
in the Screen() ?? after passing the
onItemClicked: () -> Unit
until AddSupplementItem() ?
Well. I called
navController.navigateToSupplementSearch()
in the NutritionScreen() and it crashes..
i
The big shift is Compose is state in, events out: https://developer.android.com/jetpack/compose/mental-model#paradigm
Every layer below your
RootNavGraph
shouldn't know anything about
NavController
at all. It should be lambdas all the way down so that the leaf node just triggers an event that goes up the hierarchy until you get to the layer that can handle that event
which, for navigation events, are events outside of any individual screen - no screen should know anything about navigation at all
That's why Slot based APIs are so useful in reducing the number of layers you have: https://chris.banes.me/posts/slotting-in-with-compose-ui/
c
@Ian Lake So, you mean I should naviagtion in NavGraph? For example,
Copy code
appBarGraph(
    onAddSupplementItem = {
        navController.navigateToSupplementSearch()
    }
)
like this? Well, but appBarGraph is just for bottom navigation. And I'd like to separate the graphs and add new routes in the NavHost so that I can navigate all the ways in the app, even different graphs.
i
You shouldn't have a separate graph 'just for bottom navigation', that's always been the wrong way to do things
that talk and second page I linked specifically talk about how to cross link separate graphs
c
@Ian Lake I got it. So, appBarGraph should be changed to something like mainGraph and then,
Copy code
mainGraph(
    navigationToHome ={},
    navigationToSetting = {},
    onAddSupplementItem = {
        navController.navigateToSupplementSearch()
    },
    onRemoveItem = {

    },
    // other events
)
Is this way correct?
i
that's the general idea, yes
c
Hmm. then, the parameters can be over 30...
if it has 30 different Screens..
i
This is also covered in the talk and the docs I linked - if you are navigating between screens in a subgraph, then you'd handle them at the
mainGraph
level, they wouldn't go all the way up to the
RootNavGraph
level
And there's nothing stopping you from collating all of the click listeners into a single
MainGraphState
object that you pass down as a single parameter, but at that point if you can't figure out what screens link to other screens and conceptualize that into small enough pieces, maybe your users are just as confused about your navigation model 🙃