导航组件:找不到 NavController

Posted

技术标签:

【中文标题】导航组件:找不到 NavController【英文标题】:Navigation Component: Cannot find NavController 【发布时间】:2019-05-22 23:18:47 【问题描述】:

我正在使用导航组件在我的应用程序中导航。它在片段内工作正常,但无法在包含实际导航主机的活动中找到导航主机。

当用户单击 FAB 时,我试图打开一个新片段,我将它包含在 Main 活动的 XML 中。当我调用 findNavController() 时,它找不到控制器。导航主机控制器位于 XML 布局中。我不明白为什么它找不到它。

主活动

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)

        
    

活动主 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_
        android:layout_
        tools:context=".domain.MainActivity"
        android:animateLayoutChanges="true">

    <com.google.android.material.appbar.AppBarLayout
            android:layout_
            android:layout_
            android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_
                android:layout_
                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_
                android:layout_>

            <com.google.android.material.tabs.TabItem
                    android:text="Test 1"
                    android:layout_
                    android:layout_/>

            <com.google.android.material.tabs.TabItem
                    android:text="Test 2"
                    android:layout_
                    android:layout_/>
        </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_
        android:layout_
        app:defaultNavHost="true"
        app:navGraph="@navigation/main_navigation" />


    <com.google.android.material.bottomappbar.BottomAppBar
            android:id="@+id/bar"
            android:layout_
            android:layout_
            android:layout_gravity="bottom"/>


    <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_
            android:layout_
            app:layout_anchorGravity="right|top"
            app:layout_anchor="@+id/bar"
            android:src="@drawable/ic_add_black_24dp"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

【问题讨论】:

I can't understand why it fails to find it. 是否返回null 是的,它返回空值。我设法找到了解决方案。我会把它作为答案,所以它更具可读性 Navigation.findNavController( this, R.id.nav_host) .navigate(R.id.addNewWorkoutFragment) 尝试使用它应该可以工作 我也试过了,但是没用。我已经发布了我的解决方案。 您可以尝试在活动的onStart() 中设置 OnClickListener 并检查。您的解决方案似乎是个 hack。 【参考方案1】:

在我设法以这种方式获取 navController 之前,我遇到了同样的异常:

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

从此answer获得:

在找到导航控制器之前,如果您使用绑定,则需要设置视图:

binding = BaseLayoutBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)

如果没有:

setContentView(R.layout.activity_main)

对片段使用相应的绑定。

【讨论】:

这实际上是导航组件文档中所述:developer.android.com/guide/navigation/…“当使用 FragmentContainerView 创建 NavHostFragment 或通过 FragmentTransaction 手动将 NavHostFragment 添加到您的活动时,尝试在 onCreate( ) 通过 Navigation.findNavController(Activity, @IdRes int) 的 Activity 将失败。您应该直接从 NavHostFragment 检索 NavController。" Before finding the nav controller, you need to set the view 这对我有帮助。【参考方案2】:

尝试在onCreate 的Activity 的onStart 中设置Fab 按钮的onClickListener,就像在onCreate 中一样,Activity 只是在膨胀视图并且没有设置NavHostController。因此,如果您在活动的 onStart 中设置 onClickListener 将按预期工作。

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)
    
  

【讨论】:

现在 SOF 有thank's feature旁边回答你可以使用它。 :P 反正是你的厕所 @KhamidjonKhamidov 是的,在 onCreate() 中它崩溃了,但在 onStart() 中它工作正常。 奇怪的是,我在一个新的Bottom Navigation Activity 项目中遇到了同样的问题。将导航控制器逻辑移动到 onStart() 就像这样解决了问题!【参考方案3】:

在 Java 中,您可以通过这种方式在活动中找到 NavController

Navigation.findNavController(this,R.id.nav_host).navigate(R.id.YourFragment);

【讨论】:

【参考方案4】:

原来拥有导航控制器的活动...没有导航组件。

解决方案是手动将 NavController 设置为 Activity 中包含的每个视图。

val navController = findNavController(R.id.nav_host_fragment)
Navigation.setViewNavController(fab, navController)

现在这可以工作了:

fab.setOnClickListener 

    it.findNavController().navigate(R.id.addNewWorkoutFragment)


我仍然不明白为什么它的工作方式如此,所以任何解释都非常受欢迎:)

到目前为止,Android API 根本没有多大意义。

来源:Navigate to fragment on FAB click (Navigation Architecture Components)

【讨论】:

【参考方案5】:

你仍然可以通过这样做在你的 oncreate 中获得访问权限

    //the id would be the id of the Fragment Element In Your Activity XML File
    val navGraph = Navigation.findNavController(this, R.id.activity_main)
    binding.mainFab.setOnClickListener 
        navGraph.navigate(R.id.destinationFragment)
    

【讨论】:

【参考方案6】:

问题可能是 FAB 被添加到活动或与 NavHost 片段使用的片段不同的片段。在这种情况下,当您调用it.findNavController() 时,它找不到导航控制器。

您可以检查您的 FAB 是否属于 NavHost 提取的片段,或者调用 Activity 的 findNavController(&lt;id&gt;) 并将您正在查找的片段的 id 传递给它

override fun onCreate(savedInstanceState: Bundle?) 
        ...
        fab.setOnClickListener 
            findNavController(R.id.nav_host_fragment)
                .navigate(R.id.addNewWorkoutFragment)

        
    

【讨论】:

【参考方案7】:

我发现这个答案很有帮助。在您的活动中粘贴此代码

Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.yourDestination)

【讨论】:

【参考方案8】:

这是 Kotlin 的扩展版本:

 fun AppCompatActivity.findNavController(
    @IdRes navHostViewId: Int
): NavController 
    val navHostFragment =
        supportFragmentManager.findFragmentById(navHostViewId) as NavHostFragment

    return navHostFragment.navController

navHostViewId 是您的androidx.fragment.app.FragmentContainerView 的 ID。

【讨论】:

【参考方案9】:

在Activity的OnCreate中访问navController最好的方式是在inflating布局后访问 可以通过kotlin扩展函数doOnPreDraw()

来实现
class MainActivity : AppCompatActivity() 

    private lateinit var binding: ActivityMainBinding

    private val navController: NavController
        get() = Navigation.findNavController(this, R.id.nav_host_fragment)

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.root.doOnPreDraw 
            // here you can safely use navController
            binding.toolbar.setupWithNavController(navController)
        
    

【讨论】:

【参考方案10】:

仅限 Kotlin

Android Navigation KTX为Activity提供了扩展功能

我所要做的就是

findNavController(R.id.myNavHostFragment).navigate(R.id.to_someFragment)

我的app/gradle.build.kts 文件中有以下依赖项(

implementation ("androidx.navigation:navigation-fragment-ktx:2.3.5")
implementation ("androidx.navigation:navigation-runtime-ktx:2.3.5")
implementation ("androidx.navigation:navigation-ui-ktx:2.3.5")

使用路线

您也可以使用生成的Directions 类。由于这是一个全局操作,Directions 类位于 NavigationDirections.to_someFragment()

//very useful if you're passing args then you could do something like
//NavigationDirections.to_someFragment(myArg)    
NavigationDirections.to_someFragment()findNavController(R.id.myNavHostFragment).navigate(NavigationDirections.to_someFragment())

附注具体的扩展功能来自runtime-ktxaar

【讨论】:

以上是关于导航组件:找不到 NavController的主要内容,如果未能解决你的问题,请参考以下文章

导航组件:找不到NavController

用酶浅渲染找不到元素

如何修复生产中找不到的 vue 动态异步组件?

获取 ReferenceError:找不到变量:由于 onPress 中的方法而导致的 TouchableOpacity

我的应用找不到导航器变量 - “ReferenceError:找不到变量:导航器”

Android 导航架构组件:如何将捆绑数据传递给 startDestination