具有FragmentContainerView的NavHostFragment/NavController为Null应为



使用导航UI的BottomNavigationViewFragmentContainerView创建底部应用程序栏导航,类似于示例应用程序NavigationAdadvancedSample。

请注意,NavigationAndvancedSample应用程序似乎没有使用文档中描述的相同实现,因为它有一个使用自定义扩展方法setupWithNavController的变通实现。

观察到

使用FragmentContainerViewMainActivity.kt中创建BottomNavigationView时,NavHostFragment为空。

BottomNavigationViewSample存储库中提供了可重复的错误和完整的代码示例

错误

2020-05-15 12:39:19.117 18747-18747/com.example.bottomnavigationviewsample E/AndroidRuntime:致命异常:main流程:com.example.bottomnavigationviewsample,PID:18747java.lang.RuntimeException:无法在android.app.ActivityThread.performLaunchActivity(ActivityThreads.java:3270)上启动活动ComponentInfo{com.example.pottomnavigationviewsample.com/example.pottottomnavigationviewsample.MainActivity}:kotlin.TypeCastException:null不能转换为非null类型androidx.navigation.frage.NavHostFragment在android.app.ActivityThread.handleLaunchActivity(ActivityThreads.java:3409)在android.app.servertransaction.LaunchActivityItem.exexecute(LaunchActivityItem.java:83)在android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)在android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)在android.app.ActivityThread$H.handleMessage(ActivityThreads.java:2016)在android.os.Handler.dispatchMessage(Handler.java:107)在android.os.Looper.loop(Looper.java:214)在android.app.ActivityThread.main(ActivityThreads.java:7356)位于java.lang.reflect.Method.ioke(本机方法)网址:com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:930)由:kotlin引起。TypeCastException:null不能强制转换为非null类型androidx.navigation.fragment.NavHostFragment网址:com.example.bottomnavigationviewsample.MainActivity.onCreate(MainActivity.kt:16)在android.app.Activity.performCreate(Activity.java:7802)在android.app.Activity.performCreate(Activity.java:7791)在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)在android.app.ActivityThread.performLaunchActivity(ActivityThreads.java:3245)在android.app.ActivityThread.handleLaunchActivity(ActivityThreads.java:3409)在android.app.servertransaction.LaunchActivityItem.exexecute(LaunchActivityItem.java:83)在android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)在android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)在android.app.ActivityThread$H.handleMessage(ActivityThreads.java:2016)在android.os.Handler.dispatchMessage(Handler.java:107)在android.os.Looper.loop(Looper.java:214)在android.app.ActivityThread.main(ActivityThreads.java:7356)位于java.lang.reflect.Method.ioke(本机方法)网址:com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:930)2020-05-15 12:39:19.132 18747-18747/com.example.bottomnavigationviewsample I/Process:发送信号。PID:18747 SIG:9

实现

  1. 为第一个视图home.xml创建一个导航图,以显示在app>res>navigation下的BottomNavigationView中。

    a。当系统提示添加项目依赖项时,选择确定

    b。将kotlinOptions { jvmTarget = '1.8' }添加到build.gradle(:someAppModule)以启用AppBarConfiguration的内联字节码。

    c。向home.xml添加一个片段以显示在BottomNavigationView中。

home.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/home"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.bottomnavigationviewsample.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" />
</navigation>

build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
kotlinOptions { jvmTarget = '1.8' }
defaultConfig {
applicationId "com.example.bottomnavigationviewsample"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
}
  1. app>res>菜单下为BottomNavigationViewbottom_nav.xml创建菜单。

    a。为菜单idtitle添加字符串值。

    b。为菜单icon添加矢量绘图。

bottom_nav.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/home"
android:icon="@drawable/ic_home_black_24dp"
android:contentDescription="@string/cd_home"
android:title="@string/title_home" />
</menu>
  1. FragmentContainerViewBottomNavigationView添加到MainActivity.ktactivity_main.xml布局中

activity_main.xml

<LinearLayout 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_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav"/>
</LinearLayout>
  1. MainActivity.kt.中启用BottomNavigationView

    a。创建AppBarConfiguration请参阅:使用NaviationUI>AppBarConfiguration更新UI组件

    b。创建NavHostFragmentNavController请参阅:使用findNavController的FragmentContainerView的StackOverflow解决方案

    c。设置操作栏导航。

    d。设置BottomNavigationView导航请参阅:使用NavigationUI>底部导航更新UI组件

MainActivity.kt

package com.example.bottomnavigationviewsample
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appBarConfiguration = AppBarConfiguration(setOf(R.id.home))
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_container) as NavHostFragment
val navController = navHostFragment.navController
setupActionBarWithNavController(navController, appBarConfiguration)
bottom_nav.setupWithNavController(navController)
}
}

尝试的解决方案

  1. 如文档中所述,使用findNavController(R.id.nav_host_container)创建NavController

  2. 实现fragment视图,而不是activity_main.xml.中的FragmentContainerView

activity_main.xml

<LinearLayout 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_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav"/>
</LinearLayout>

我也遇到了这个问题。我的错误是没有在导航文件中为导航标记输入正确的ID。请注意,ID必须等于菜单项的ID。

在导航文件(navigation/home.xml)中:

<navigation
android:id="@+id/home" ... >

以及在菜单文件(menu/bottom_nav.xml)中:

<item
android:id="@+id/home" ... />

BottomNavigationView菜单项添加父导航图

完整的示例代码包含在BottomNavigationSample中。

  1. 为菜单片段创建父级导航图。请注意,NavigationAdvancedSample体系结构模式没有反映这一点,该模式有三个单独的导航图,没有父导航图

这可以通过一个父导航图和每个菜单项的片段或嵌套导航图来实现。嵌套导航图很好,因为每个子流都可以在嵌套图中组织。

main.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
app:startDestination="@id/home">
<include app:graph="@navigation/home" />
<include app:graph="@navigation/saved" />
</navigation>
  1. FragmentContainerView中使用navGraph添加父图形

activity_main.xml

<LinearLayout 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_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/main"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav" />
</LinearLayout>
  1. MainActivity.kt中启用BottomNavigationView
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appBarConfiguration = AppBarConfiguration(setOf(R.id.home, R.id.saved))
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_container) as NavHostFragment
val navController = navHostFragment.navController
setupActionBarWithNavController(navController, appBarConfiguration)
bottom_nav.setupWithNavController(navController)
}
}

最新更新