导航组件:找不到 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(<id>)
并将您正在查找的片段的 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-ktx
aar
【讨论】:
以上是关于导航组件:找不到 NavController的主要内容,如果未能解决你的问题,请参考以下文章
获取 ReferenceError:找不到变量:由于 onPress 中的方法而导致的 TouchableOpacity