IllegalStateException: 链接没有 NavController 集

我正在使用 Android 导航组件进行导航。我有一个 LoginFragment,它有一个按钮可以转换到 SignUpFragment。在点击按钮时,我得到了这个错误。

java.lang.IllegalStateException: View android.support.v7.widget.AppCompatButton{49d9bd1 VFED..C.. ...P.... 201,917-782,1061 #7f090172 app:id/signUpLink} does not have a NavController set

这是我的 nav _ graph. xml

<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="org.fossasia.openevent.app.core.auth.login.LoginFragment"
android:label="login_fragment"
tools:layout="@layout/login_fragment">
<action
android:id="@+id/action_loginFragment_to_signUpFragment"
app:destination="@id/signUpFragment" />


</fragment>
</navigation>

以下是 LoginFragment 中的代码,用于导航-

binding.signUpLink.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_loginFragment_to_signUpFragment, null));

下面是 NavHostFragment-的活动布局文件的摘录

<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:name="android.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_navigation"
app:defaultNavHost="true"/>
117576 次浏览

更新解决方案

实际上,导航系统在 FrameLayout 中找不到 NavController,所以用 <fragment>代替 <FrameLayout>就可以了。

<fragment>标记中添加以下内容-

android:name="androidx.navigation.fragment.NavHostFragment"

完成更改后,代码看起来将类似于-

 <fragment
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_navigation"
app:defaultNavHost="true"/>

使用片段视图,如 onViewCreated

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)


val navController = Navigation.findNavController(view)


binding.signUpLink.setOnClickListener {
navController.navigate(R.id.action_loginFragment_to_signUpFragment)
}

我也面临同样的问题。 所以,与其这样,

binding.signUpLink.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_loginFragment_to_signUpFragment, null));

我用我的 NavHostFragment找到了 NavHostFragment:

Button button = (Button)findViewById(R.id.button);


button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {


Fragment navhost = getSupportFragmentManager().findFragmentById(R.id.fragment2);
NavController c = NavHostFragment.findNavController(navhost);
c.navigate(R.id.firstFragment);




}
});

fragment2navhostfragmentID

一件奇怪的事情发生在我身上,在代码片段下面,正常流程是从 Fragment1到 bragment2,但是在进入 bragment1并再次导航 bragment2之后,出现了“导航控制器未设置为视图”错误。

    binding.ivIcon.setOnClickListener(v -> {
Openfragment2(v);});


private void Openfragment2(View view) {
Navigation.findNavController(binding.ivIcon).navigate(R.id.fragment2);


}

在 findNavController 中,需要传递 onclick 视图,这就是问题所在。

private void Openfragment2(View view) {
Navigation.findNavController(view).navigate(R.id.fragment2);


}

在做了一些研究之后,我发现了 这个问题也在谷歌的错误追踪器上。 这是 Java 的官方解决方案:

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
.findFragmentById(R.id.nav_host_fragment);
NavController navCo = navHostFragment.getNavController();

在 Kotlin:

val navHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

官方推荐的解决方案

目前使用 FragmentContainerView 并不是很友好,您必须通过 SupportFragmentManager 访问它:

val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

在 xml 中,我的 FragmentContainerView 如下所示:

<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:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:navGraph="@navigation/nav_graph"
/>

这已经在 androidx 导航版本 2.3.0中进行了测试

我已经删除了旧的答案,因为谷歌开发人员已经澄清,它不再是推荐的解决方案。谢谢@JustLearnedit 发表评论,让我更新这个问题。

我刚才面对这个问题,但我确信我的代码,然后意识到我已经改变了位置的碎片从下面的主软件包到另一个文件夹

所以 我用 Build-> clean 然后 Build-> make project 解决了这个问题,让 IDE 改变了它的 Directions 类

在 Java 中试试下面这行:

Navigation.findNavController(findViewById(R.id.nav_host_fragment)).navigate(R.id.first_fragment);

原因是如果您使用 FragmentContainerView(或者只使用 FrameLayout)添加片段视图,那么在 Activity.onCreate()方法内部就不可用。在这种情况下,获取 NavController的正确方法是查找 NavHostFragment并从中获取控制器。参见 问题解释

override fun onCreate(savedInstanceState: Bundle?) {
...


val navHostFragment = supportFragmentManager.findFragmentById(R.id.my_fragment_container_view_id) as NavHostFragment
val navController = navHostFragment.navController
}

不要像其他一些答案建议的那样使用 <fragment>而不是 <androidx.fragment.app.FragmentContainerView>。在上面提到的问题中,请参见 Google 团队的 评论

应该始终使用 FragmentContainerView。当一个片段的根布局直接在其他布局(如 ConstraintLayout)中时,除了通过标签添加的片段在生命周期中的状态完全不同于添加到 FragmentManager 中的其他片段之外,绝对还有其他关于窗口插入和布局问题的修复。Lint 检查就在那里,因为在任何情况下都绝对应该切换到 FragmentContainerView。

还有一个来自 AndroidDevSummit 2019的 公告,它解释了为什么引入 FragmentContainerView,以及另一个关于差异的线程: 作为 NavHost 的视图

在我的案例中,它是由 android 工作室完成的..。

<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:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />


上面的代码是由下面的警告所替换的工作代码!

<androidx.fragment.app.FragmentContainerView
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:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />

在我的情况下,我改变了我的代码

val action =
StartFragmentDirections.actionStartFragmentToLoginFragment()
Navigation.findNavController(view).navigate(action);

onViewCreated()

我犯了以下错误:

MainActivity@9ff856没有将 NavController 设置为2131230894

我使用的是底部导航视图:

以下几点对我很有效:

val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)


val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment)
val navController = navHostFragment?.findNavController()
if (navController != null) {
bottomNavigationView.setupWithNavController(navController)
}

<fragment>代替 <FrameLayout>,用 android:name="androidx.navigation.fragment.NavHostFragment"代替 android:name="org.fossasia.openevent.app.core.auth.login.LoginFragment"

这个代码对 Kotlin 来说应该能正常工作

val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_loginFlow_fragment) as NavHostFragment
val navController = navHostFragment.navController
navController.navigate(R.id.to_dictionaryDownload1)

在我的例子中(我使用的是 BottomNavigation) ,在 findNavController中我添加的是 Framlayout Id!你应该像这样添加 fragment ID:

在 xml 中:

<FrameLayout
android:id="@+id/container_orders"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bnv_main"
android:visibility="gone">


<fragment
android:id="@+id/nav_orders"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false" />


</FrameLayout>

Kotlin 班级:

private val navOrdersController by lazy {
mainActivity.findNavController(R.id.nav_orders).apply {
graph = navInflater.inflate(R.navigation.main_navigation_graph).apply {
startDestination = startDestinations.getValue(R.id.action_history)
}
}
}

Private latinit var 装订: ActivityNewsBinding

新闻视图模型

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_news)
binding = ActivityNewsBinding.inflate(layoutInflater)
setContentView(binding.root)


val newsrepository = NewsRepository(ArticleDatabase(this))
val viewModelProviderFactory = NewsViewModelProviderFactory(newsrepository)
viewModel = ViewModelProvider(this,viewModelProviderFactory).get(NewsViewModel::class.java)


    

val navHostFragment = supportFragmentManager.findFragmentById(R.id.newsNavHostFragment) as NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavigationView.setupWithNavController(navController)




}

更新了 FragmentViewContainer 的答案

确保你有

android:name="androidx.navigation.fragment.NavHostFragment"

而不是您想要作为开始片段的片段。 (启动目的地在导航图中定义)。