问题
I am using Navigation Component for navigating in my app. It works fine inside fragments but it fails to find the nav host in the activity that holds the actual navigation host.
I am trying to open a new fragment when the user clicks on FAB, which I included in Main activity's XML. When I call findNavController() it fails to find the controller. The nav host controller is in the XML layout. I can't understand why it fails to find it.
MainActivity
class MainActivity : AppCompatActivity(), OnActivityComponentRequest {
override fun getTabLayout(): TabLayout {
return this.tabLayout
}
override fun getFap(): FloatingActionButton {
return this.floatingActionButton
}
private lateinit var tabLayout: TabLayout
private lateinit var floatingActionButton: FloatingActionButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
this.tabLayout = tabs
this.floatingActionButton = fab
fab.setOnClickListener {
it.findNavController().navigate(R.id.addNewWorkoutFragment)
}
}
}
Activity main XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".domain.MainActivity"
android:animateLayoutChanges="true">
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabItem
android:text="Test 1"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
<com.google.android.material.tabs.TabItem
android:text="Test 2"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchorGravity="right|top"
app:layout_anchor="@+id/bar"
android:src="@drawable/ic_add_black_24dp"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
回答1:
Try setting up onClickListener of Fab button in onStart of the Activity as in onCreate Activity is just inflating the View and haven't set the NavHostController. So if you setup onClickListener in onStart of activity is will work as expected.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
this.tabLayout = tabs
this.floatingActionButton = fab
}
override fun onStart() {
super.onStart()
floatingActionButton.setOnClickListener {
it.findNavController().navigate(R.id.addNewWorkoutFragment)
}
}
回答2:
Turns out that activity that holds navigation controller... doesn't have navigation component.
The solution is to manually set the NavController to each view contained in the activity.
val navController = findNavController(R.id.nav_host_fragment)
Navigation.setViewNavController(fab, navController)
Now this would work:
fab.setOnClickListener {
it.findNavController().navigate(R.id.addNewWorkoutFragment)
}
I still don't understand why this works the way it works so any explanation would be more than welcome :)
As of now, Android API simply doesn't make much sense.
Source: Navigate to fragment on FAB click (Navigation Architecture Components)
回答3:
The problem might be that FAB was added to the activity or a fragment different from the one used by NavHost fragment. In this case, when you call it.findNavController() it cannot find the navigation controller.
You can either check that your FAB belongs to the fragment pulled by NavHost or call an Activity's findNavController(<id>) and pass it id of the fragment you're looking up
override fun onCreate(savedInstanceState: Bundle?) {
...
fab.setOnClickListener {
findNavController(R.id.nav_host_fragment)
.navigate(R.id.R.id.addNewWorkoutFragment)
}
}
回答4:
In Java you can find NavController inside activity this way:
Navigation.findNavController(this,R.id.nav_host).navigate(R.id.YourFragment);
来源:https://stackoverflow.com/questions/53902494/navigation-component-cannot-find-navcontroller