IllegalStateException:链接没有设置 NavController

Posted

技术标签:

【中文标题】IllegalStateException:链接没有设置 NavController【英文标题】:IllegalStateException: Link does not have a NavController set 【发布时间】:2018-11-03 06:19:40 【问题描述】:

我正在使用 android 导航组件进行导航。我有一个 LoginFragment,它有一个转换为 SignUpFragment 的按钮。单击按钮时出现此错误。

java.lang.IllegalStateException: View android.support.v7.widget.AppCompatButton49d9bd1 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_
    android:layout_
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:name="android.navigation.fragment.NavHostFragment"
    app:navGraph="@navigation/main_navigation"
    app:defaultNavHost="true"/>

【问题讨论】:

我也遇到过这个问题。但在我的情况下,错误是因为我错误地将按钮放置在 _activity.xml 文件中,与“androidx.navigation.fragment.NavHostFragment”片段位于同一级别,而不是在 _fragment.xml 文件中。现在我将“按钮”移动到 _fragment.xml 文件,它正在工作。我不确定这对你有没有帮助。只是分享我遇到的问题:-) 确保你使用fragment元素而不是其他布局元素 内部 onCreate() 方法从下面的链接访问 navController 使用解决方案这对我有用***.com/questions/59275009/… 【参考方案1】:

官方推荐的解决方案

目前使用 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_
    android:layout_
    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

我已删除旧答案,因为 Google 开发人员已澄清它不再是推荐的解决方案。感谢@Justlearnedit,您发表评论允许我更新此问题。

【讨论】:

看看这里为什么这可能是个好建议:***.com/questions/58703451/… 在链接的问题中,他们讨论了为什么你不应该使用片段:issuetracker.google.com/issues/142847973#comment15:Lint 检查正是因为你绝对应该在所有情况下切换到 FragmentContainerView。 @Justlearnedit 谢谢,当我发布这个答案时还不清楚。感谢您更新我,我已经测试了推荐的解决方案,并确保更新帖子以反映它。 推荐的解决方案在 Nav 2.3.3 上对我有用,感谢您指出这一点! 很棒的朋友【参考方案2】:

更新的解决方案

其实Navigation在FrameLayout中找不到NavController。所以用&lt;fragment&gt;替换&lt;FrameLayout&gt;就可以了

&lt;fragment&gt;标签内添加以下内容-

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

修改完成后,代码将如下所示 -

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

【讨论】:

这工作正常,但会在使用 标记时发出 lint 警告,说明应该用 FragmentContainerView 替换它(尽管这样做会使您的应用程序崩溃)。跨度> android:name="androidx.navigation.fragment.NavHostFragment" @Peter 我能够通过将材料的 gradle 依赖关系升级到 implementation 'com.google.android.material:material:1.2.0-alpha04' 来解决这个问题。 对 FragmentContainerView 有异常,但对 Fragment 工作正常。此外,当使用 FragmentContainerView 时,它会发出 lint 警告 app:navGraph 未设置,但片段没有此类警告 检查此答案及其 cmets:***.com/a/59275182/421467【参考方案3】:

在做了一些研究后,我发现了this Issue also on Google's bugtracker。 所以这里是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

【讨论】:

与 Java 和 FragmentContainerView 完美配合。 (nav_version = "2.3.0") 不知何故解决了我的问题。【参考方案4】:

原因是如果您使用FragmentContainerView(或仅使用FrameLayout)添加片段视图,则在Activity.onCreate() 方法中不可用。在这种情况下获取NavController 的正确方法是找到NavHostFragment 并从中获取控制器。请参阅issue 和explanation。

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

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

不要使用 &lt;fragment&gt; 而不是 &lt;androidx.fragment.app.FragmentContainerView&gt; 正如其他一些答案所建议的那样。请参阅我上面提到的问题中来自 Google 团队的comment。

您应该始终使用 FragmentContainerView。当片段的根布局直接位于其他布局(如 ConstraintLayout)中时,除了通过该标签添加的片段经历与其他片段完全不同的生命周期状态的标签的潜在问题外,绝对还有其他解决方案围绕窗口插入和布局问题发生添加到 FragmentManager。 Lint 检查的存在正是因为您绝对应该在所有情况下切换到 FragmentContainerView。

还有一个来自 AndroidDevSummit 2019 的 announcement 解释了为什么引入了 FragmentContainerView,以及关于差异的另一个线程:<androidx.fragment.app.FragmentContainerView> vs as a view for a NavHost

【讨论】:

很好的解释。 扩展怎么样? ***.com/questions/69190134/…【参考方案5】:

只需将&lt;FrameLayout&gt; 替换为&lt;fragment&gt; 并将android:name="org.fossasia.openevent.app.core.auth.login.LoginFragment" 替换为android:name="androidx.navigation.fragment.NavHostFragment"

【讨论】:

【参考方案6】:

使用onViewCreated等fragment的视图

 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)
    

【讨论】:

对我来说不幸的是这并不能解决问题 - 实际上是一样的【参考方案7】:

我遇到了同样的问题。 所以,而不是这个,

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

【讨论】:

【参考方案8】:

在我的情况下,它是由 android studio 完成的......

<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_
        android:layout_
        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_
        android:layout_
        app:defaultNavHost="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

【讨论】:

【参考方案9】:

在 Java 中尝试以下行:

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

【讨论】:

哇!!经过两天的大量搜索,各位哥们解决了我的问题。谢谢【参考方案10】:

我遇到了以下错误:

MainActivity@9ff856 没有在 2131230894 上设置 NavController

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

以下内容对我有用:

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

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

【讨论】:

【参考方案11】:

我发生了一件奇怪的事情,下面的代码 sn-p 正在处理从 Fragment1 到 Fragment2 的正常流程,但是在到达 Fragment1 并再次导航 Fragment2 之后,这引发了“未为视图设置导航控制器”错误.

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

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


这里的问题在视图中,在 findNavController 中需要传递 onclicked 视图。

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


【讨论】:

【参考方案12】:

我刚才遇到了这个问题,但我确定我的代码然后意识到我已经将片段的位置从主包下更改到另一个文件夹

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

【讨论】:

我已经 cleanedbuildrebuild 但仍然无法正常工作。【参考方案13】:

这段代码应该适用于 kotlin

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

【讨论】:

【参考方案14】:

就我而言,我更改了我的代码

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

onViewCreated()

【讨论】:

【参考方案15】:

就我而言(我使用的是BottomNavigation),在findNavController 中,我添加了Framlayout Id!你应该像这样添加fragment Id:

在我的 xml 中:

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

            <fragment
                android:id="@+id/nav_orders"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_
                android:layout_
                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)
            
        
    

【讨论】:

以上是关于IllegalStateException:链接没有设置 NavController的主要内容,如果未能解决你的问题,请参考以下文章

异常Caused by: java.lang.IllegalStateException: Method has too many Body parameters

SpringBoot + Mybatis + MySQL,java.lang.IllegalStateException:无法加载ApplicationContext

java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleExcepti

异常:java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/app/userInf

批量下载的实现及java.lang.IllegalStateException异常

ElasticSearch出现java.lang.IllegalStateException: duplicate plugin: - Plugin information: