Reputation: 641
I am currently implementing the Navigation Component into my app but it seems finding the NavHostFragment just doesn't work no matter what I do.
I have tried, rebuilding, invalidating, and restarting, changing the names around, and updating my Android Studio but nothing seems to work. I think this is also the reason why I get an error when trying to get the NavController in my MainActivity.kt
file as it returns null.
Android Studio version 4.0.1
nav_graph.xml image:
nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.movieapp.ui.main.MainFragment"
android:label="MainFragment">
<action
android:id="@+id/action_mainFragment_to_searchMovieFragment"
app:destination="@id/searchMovieFragment" />
</fragment>
<fragment
android:id="@+id/searchMovieFragment"
android:name="com.example.movieapp.ui.search.SearchMovieFragment"
android:label="SearchMovieFragment" />
</navigation>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<include
layout="@layout/appbar" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private val navController by lazy {
(supportFragmentManager.findFragmentById(R.id.main_fragment) as NavHostFragment).navController
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
toolbar = findViewById(R.id.mainToolBar)
setSupportActionBar(toolbar)
setupActionBarWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.main_menu_bar, menu)
return true
}
}
build.gradle (:app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.app"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
dataBinding {
enabled true
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
// Retrofit Libraries
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
// Picasso Library
implementation 'com.squareup.picasso:picasso:2.71828'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Navigation libraries
def nav_version = "2.3.0"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
Upvotes: 16
Views: 16888
Reputation: 1
You should try adding the namespace to the view
android:name="androidx.navigation.fragment.NavHostFragment"
Example -
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/navgraph" />
Upvotes: 0
Reputation: 1
Here is how you can solve that problem.
// TODO: Screen enum, enum class LunchTrayScreen(@StringRes val title: Int){,Start(title = R.string.app_name),,Entree(title = R.string.choose_entree),,SideDish(title = R.string.choose_side_dish),Accompaniment(title =R.string.choose_accompaniment), Checkout(title = R.string.order_checkout)}
// TODO: AppBar
@Composable fun LunchTrayApp() {// TODO: Create Controller and initialization val navController = rememberNavController(),val backStackEntry by navController.currentBackStackEntryAsState(),val currentScreen = LunchTrayScreen.valueOf(backStackEntry?.destination?.route ?:LunchTrayScreen.Start.name)// Create ViewModel,val viewModel: OrderViewModel = viewModel()
Scaffold(topBar = {LunchTrayAppBar(currentScreenTitle = currentScreen.title,canNavigateBack = navController.previousBackStackEntry != null,navigateUp = { navController.navigateUp() })) { innerPadding -> val uiState by viewModel.uiState.collectAsState()
// TODO: Navigation host NavHost(navController = navController,startDestination = LunchTrayScreen.Start.name,modifier = Modifier.padding(innerPadding) ){composable(route = LunchTrayScreen.Start.name){StartOrderScreen(onStartOrderButtonClicked = {navController.navigate(LunchTrayScreen.Entree.name)})} composable(route = LunchTrayScreen.Entree.name){ EntreeMenuScreen( options = com.example.lunchtray.datasource.DataSource.entreeMenuItems, onCancelButtonClicked = { viewModel.resetOrder(), navController.popBackStack(LunchTrayScreen.Start.name, inclusive = false)},onNextButtonClicked = {navController.navigate(LunchTrayScreen.SideDish.name) },onSelectionChanged = { item -> viewModel.updateEntree(item)})} composable(route = LunchTrayScreen.SideDish.name){SideDishMenuScreen( options =com.example.lunchtray.datasource.DataSource.sideDishMenuItems, onCancelButtonClicked = { viewModel.resetOrder() navController.popBackStack(LunchTrayScreen.Start.name, inclusive = false)},onNextButtonClicked = { navController.navigate(LunchTrayScreen.Accompaniment.name) },onSelectionChanged = { item -> viewModel.updateSideDish(item)} )}composable(route = LunchTrayScreen.Accompaniment.name){AccompanimentMenuScreen(options = com.example.lunchtray.datasource.DataSource.accompanimentMenuItems,onCancelButtonClicked = { viewModel.resetOrder() navController.popBackStack(LunchTrayScreen.Start.name, inclusive = false)},onNextButtonClicked = {navController.navigate(LunchTrayScreen.Checkout.name) },onSelectionChanged = { item -> viewModel.updateAccompaniment(item)} )}composable(route = LunchTrayScreen.Checkout.name){CheckoutScreen(orderUiState = uiState,onNextButtonClicked = { viewModel.resetOrder()navController.popBackStack(LunchTrayScreen.Start.name, inclusive = false)},onCancelButtonClicked = { viewModel.resetOrder()navController.popBackStack(LunchTrayScreen.Start.name, inclusive = false)}) }}}}
@Composablefun LunchTrayAppBar(@StringRes currentScreenTitle: Int, canNavigateBack : Boolean,navigateUp: () -> Unit,modifier : Modifier = Modifier){TopAppBar (title = { Text(stringResource(currentScreenTitle))},modifier = modifier,navigationIcon = {if(canNavigateBack){IconButton(onClick = navigateUp){Icon(imageVector = Icons.Filled.ArrowBack,contentDescription = stringResource(id = R.string.back_button) )}}})}
Another example would be: za currentScreen you will write CupcakeScreen//from enum class @Composablefun CupcakeApp(viewModel: OrderViewModel = viewModel(),navController: NavHostController = rememberNavController() ) {val backStackEntry by navController.currentBackStackEntryAsState() val currentScreen = CupcakeScreen.valueOf(backStackEntry?.destination?.route ?: CupcakeScreen.Start.name)Scaffold(topBar = {CupcakeAppBar(currentScreen = currentScreen,canNavigateBack = navController.previousBackStackEntry != null,navigateUp = { navController.navigateUp() } )} ) { innerPadding ->val uiState by viewModel.uiState.collectAsState()NavHost(navController = navController,startDestination = CupcakeScreen.Start.name, modifier = Modifier.padding(innerPadding)){composable(route = CupcakeScreen.Start.name){StartOrderScreen(quantityOptions = quantityOptions,onNextButtonClicked = { viewModel.setQuantity(it) navController.navigate(CupcakeScreen.Flavor.name)})}
Upvotes: -1
Reputation: 23483
I was having this issue even though I had added all of the required name
and fragment
suggestions from above; however, when I did an invalidate cache and restart
it solved the problem.
Upvotes: 0
Reputation: 49182
Initally we dont have NavHostFragments. You pointed each fragment to each other, created movement actions but you need something to host this movement. That is where navigation host fragment
comes into play. it is NavHostFragment that sort of swaps in our fragments as necessary inside a given layout. So what layout should hold this nav fragment. it is the layout that gets inflated during the main activity. So open activity_main.xml
.
You should add Containers/NavHostFragment
When you choose NavHostFragment to drag, you will see the available host fragments.
Upvotes: 2
Reputation: 2234
we should make sure to write this line
android:name="androidx.navigation.fragment.NavHostFragment"
<androidx.fragment.app.FragmentContainerView
android:id="@+id/navController"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
Upvotes: 2
Reputation: 1697
For me I added android:name="androidx.navigation.fragment.NavHostFragment"
inside FragmentContainerView
and worked with me
Upvotes: 3
Reputation: 1601
As mentioned in Doc, You can also use the Layout Editor to add a NavHostFragment.
YOU MAY NEED TO RESTART THE ANDROID STUDIO AFTER THIS (not mentioned in the doc)
Also, you may see "fragment" instead of "FragmentContainerView" when you try to add fragment using above method.
Upvotes: 5
Reputation:
The way I was able to resolve the issue was by going to the Activity.xml and changing the fragment class/component tag from androidx.fragment.app.FragmentContainerView
to just fragment
. It then showed up in the hosts panel of the navigation graph.
Upvotes: 17
Reputation: 81
I had the same issue and I solved this by creating the NavHostFragment from the Design, Palette and then assign the respective navigation resource file.
Upvotes: 7
Reputation: 636
You can find NavController
in activity as:
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
toolbar = findViewById(R.id.mainToolBar)
setSupportActionBar(toolbar)
navController = findNavController(R.id.nav_host_fragment)
setupActionBarWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.main_menu_bar, menu)
return true
}
}
Upvotes: 3
Reputation: 1463
private val navController by lazy {
(supportFragmentManager.findFragmentById(R.id.main_fragment) as NavHostFragment).navController
}
Your navController
is null because I think supportFragmentManager.findFragmentById(R.id.main_fragment)
returns null. The id of your navHost is R.id.nav_host_fragment
according to your activity layout.
Upvotes: 2