IllegalStateException:链接没有NavController集

时间:2018-05-24 06:20:03

标签: android android-architecture-components android-architecture-navigation

我使用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 for Navigation中的代码 -

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"/>

15 个答案:

答案 0 :(得分:125)

官方推荐的解决方案

当前使用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

进行了测试

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

答案 1 :(得分:14)

我进行了一些研究,发现this Issue also on Google。 所以这是Java的官方解决方案:

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

在科特林这里:

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

答案 2 :(得分:9)

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

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团队的comment

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

AndroidDevSummit 2019中还有一个announcement,解释了为什么引入FragmentContainerView的原因,以及关于该区别的另一个主题:<androidx.fragment.app.FragmentContainerView> vs as a view for a NavHost

答案 3 :(得分:4)

实际上,导航无法在FrameLayout中找到NavController。因此,将<FrameLayout>替换为<fragment>会很好。

请记得添加

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

<fragment>标记内。

更改后,它看起来与此相似 -

 <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="android.navigation.fragment.NavHostFragment"
       app:navGraph="@navigation/main_navigation"
       app:defaultNavHost="true"/>

答案 4 :(得分:4)

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

答案 5 :(得分:3)

确保活动中的主片段的name参数设置为:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
            <div class="entry-status-overlay__inner">
                <span class="entry-status-overlay__title">Declined</span>
            </div>
        </div>

例如:

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

答案 6 :(得分:3)

在Java中,尝试以下代码:

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

答案 7 :(得分:2)

就我而言,它是由 android studio 完成的...

<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" />

答案 8 :(得分:2)

我有以下错误:

<块引用>

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

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

以下对我有用:

val bottomNavigationView = findViewById(R.id.bottomNavigationView)

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

答案 9 :(得分:1)

我遇到了同样的问题。 所以,代替这个,

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

我用navhost片段找到了navcontroller:

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);


        }
    });

fragment2是我的navhostfragmentID。

答案 10 :(得分:0)

使用片段视图,例如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)
    }

答案 11 :(得分:0)

我发生了一件奇怪的事情,下面的代码片段正在处理从Fragment1到fragment2的正常流,但是在进入fragment1并再次导航fragment2之后,这引发了“未为视图设置导航控制器”错误。 / p>

    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 :(得分:0)

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

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

答案 13 :(得分:0)

就我而言,我更改了代码

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

在 onViewCreated

答案 14 :(得分:0)

这段代码应该适用于 kotlin

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