I am using the navigation component to load my fragments like given here:
https://developer.android.com/guide/navigation/navigation-getting-started
navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_opt1,
R.id.navigation_opt2,
R.id.navigation_opt3,
R.id.navigation_more
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
I also have a Toolbar at the top with a Spinner. I want to reload/refresh the fragment & its view model when the spinner item is selected. I tried the below code for reloading but it isn't working. Also, I know we should not be using fragmentManager in Navigation Component
val ftr: FragmentTransaction = requireFragmentManager().beginTransaction()
ftr.detach(this).attach(this).commit()
Any help would be appreciated.
sorry for late reply. I am using below code for the same scenario.
That might help. call this method in your spinner ItemClick.
we have to use popbackstack for avoid adding same fragment again and again.
private fun refreshCurrentFragment(){
val id = navController.currentDestination?.id
navController.popBackStack(id!!,true)
navController.navigate(id)
}
Yes above answer https://stackoverflow.com/a/66171.. is right
if you want to reload/refresh you current fragment after perform specific operation
you have to destroy this current fragment and navigate here again
val fragmentId = findNavController().currentDestination?.id
findNavController().popBackStack(fragmentId!!,true)
findNavController().navigate(fragmentId)
Related
I have a Screen ( composable function ) that gets It's data from view model ( a list and two function to remove and add data in it ).
#Composable
fun MainScreen(
notes: List<Note>,
onAddNote: (Note) -> Unit,
onRemoveNote: (Note) -> Unit
){}
Now when i call this function inside the composable of my Nav host, I get errors stating that i should fill the parameters.
#Composable
fun NotesNavigation(){
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Navigation.MainScreen.name){
composable(Navigation.MainScreen.name){
MainScreen() // error here
}
}
}
Now I am wondering what is the best practice to sort it out, do i need to provide default values for my parameters like supplying an empty list
or
there is better way to get around it.
You can set default values to the MainScreenFunction, but since you are using navigation, this would become useless. I would suggest to set the viewmodel as a parameter. The viewmodel should still be passed through the navigation though.
I don't know if you use any dependency injection. If so, that would make it a bit easier. Then you can set it up like this:
#Composable
fun MainScreen(
viewModel: MainScreenViewModel = getViewModel() //If using Koin DI
){
...
}
This way, the navigation doesn't have to know about the viewmodel. You can still set it though, if you do need a different viewModel then the one injected for example.
I have a multi module project that uses Navigation Component to navigate between Fragments. This means that in order to get to another module, I have to launch a DeepLink using findNavController().navigate(NavDeepLinkRequest, NavOptions). When it comes time to log out of the application, I need to pop the back stack inclusive to a Destination in another module that is not visible to that module. How do I achieve this?
I had exactly the same issue and I believe Google doesn't support it by default using Navigation Component (which is sad). However I managed to do it in a bit hacky way (but it works) using old friend getIdentifier.
In your Fragment you may have a navigation request like this:
val navigateToOtherModuleRequest = NavDeepLinkRequest.Builder
.fromUri("yourapp://othermoduledestination".toUri())
.build()
Then get the resource id you need to pop-up to using getIdentifier() (it can be Fragment id or in my case nav graph id):
val homeNavGraphResourceId = resources.getIdentifier(
"home_nav_graph",
"id",
requireContext().packageName
)
Define navigationOptions like this:
val navigationOptions = NavOptions.Builder()
.setPopUpTo(
destinationId = homeNavGraphResourceId,
inclusive = true
)
.build()
And navigate using
findNavController().navigate(
navigateToOtherModuleRequest,
navigationOptions
)
Hope this will help!
I'm using NavHost and a NavHostController to navigate in my Jetpack Compose application. To specify destinations, I use string-based routes:
NavHost(
navController,
startDestination = "FOO"
) {
composable("FOO") {
Foo()
}
composable("BAR") {
Bar()
}
}
I would like to retrieve the current route as a string (FOO or BAR) using the navController. The closest alternative I can find is navController.currentDestination.id that, however, returns a numeric ID, not the route as a string.
Is there any way to retrieve this value?
I'm using Jetpack Compose beta01 and Compose Navigation alpha08.
From androidx.navigation:navigation-compose version 2.4.0-alpha01, androidx.navigation.compose.KEY_ROUTE is replaced with navBackStackEntry?.destination?.route.
The KEY_ROUTE argument has been replaced with the route property on NavDestination, allowing you to call navBackStackEntry.destination.route directly.
Release Note for 2.4.0-alpha01
Example code:
val currentRoute = navController.currentBackStackEntry?.destination?.route
Or, if you need to observe the navigation:
val navBackStackEntry by navController.currentBackStackEntryAsState()
when (val currentRoute = navBackStackEntry?.destination?.route) {
// do something with currentRoute
}
Resolved!
import androidx.navigation.compose.KEY_ROUTE
val currentRoute = navController.currentBackStackEntry?.arguments?.getString(KEY_ROUTE)
Not the cleanest solutions IMO, but it is used in the official Android documentation for navigating with compose: https://developer.android.com/jetpack/compose/navigation?hl=it
For those who have a problem with getting a route from NavDestination object, such as me. Check the class type. There are two classes of NavDestination.kt and NavDestination.java. Cast it to NavDestination.kt to be able to get the route value.
I'm trying to set up conditional navigation for my Fragments using the Navigation components and a BottomNavigationView.
Current setup (without conditions):
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
NavigationUI.setupWithNavController(bottom_navigation, navController)
General navigation is working fine, but I want to restrict user interaction with the bottom navigation based on conditions. If the condition is not met at the time of clicknig the menu item, this should only result in showing a Toast instead of navigating to the next fragment.
I already looked up this but the solution mentioned there involves navigating to the next fragment first and then check the conditions - but I want to avoid this.
Thank you very much.
Expose LiveData that will stream which #Ids are disabled.
class MainViewModel{
val disableNavigation = MutableLiveData<#Ids Int>()
fun invalidateNavigation() {
val canNavigate = ....
if(!canNavigate){
disableNavigation.value = R.id.bottom_nav_item_x
}
}
}
Then just observe this:
mainViewModel.observe(viewLifecycleOwner){
//disable the id here
//re-enable the rest of the items
}
I'm working on navigation component architecture and I face problem in how to set start destination after I authenticate user since I have two type of users :admin and user and I made my app contains 4 activities
loginActivity ,signUpActivity userMainActivity : that use navigation component and contain all fragments related to user
and adminMainActivity :that use navigation component and contain all fragments related to admin
I'm not able to figure out how to handle this and start user or admin activity after login by set default
should I put user and admin in separate navigation graph or what to in this case
you can set start destination programmatically, just like:
val navHostFragment = nav_host_fragment as NavHostFragment
val graphInflater = navHostFragment.navController.navInflater
navGraph = graphInflater.inflate(R.navigation.nav_graph)
navController = navHostFragment.navController
val destination = if (intent.getBooleanExtra(IS_ADMIN,false))
R.id.adminhomeFragment
else R.id.userhomeFragment
navGraph.startDestination = destination
navController.graph = navGraph