在 Android Studio 中 , 使用右键菜单 , 创建 " Bottom Navigation Activity " ,
创建完成后 , 启动该 Activity , 报如下错误 :
E/AndroidRuntime: FATAL EXCEPTION: main
Process: cn.zkhw.client, PID: 30022
java.lang.RuntimeException: Unable to start activity ComponentInfo{cn.zkhw.client/cn.zkhw.client.BottomNavigationActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4765)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4983)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:123)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3059)
at android.os.Handler.dispatchMessage(Handler.java:117)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:293)
at android.app.ActivityThread.loopProcess(ActivityThread.java:9934)
at android.app.ActivityThread.main(ActivityThread.java:9923)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1240)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
at androidx.navigation.ui.ActionBarOnDestinationChangedListener.setTitle(ActionBarOnDestinationChangedListener.java:48)
at androidx.navigation.ui.AbstractAppBarOnDestinationChangedListener.onDestinationChanged(AbstractAppBarOnDestinationChangedListener.java:103)
at androidx.navigation.NavController.addOnDestinationChangedListener(NavController.java:233)
at androidx.navigation.ui.NavigationUI.setupActionBarWithNavController(NavigationUI.java:227)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)
at cn.zkhw.client.BottomNavigationActivity.onCreate(BottomNavigationActivity.kt:32)
at android.app.Activity.performCreate(Activity.java:8592)
at android.app.Activity.performCreate(Activity.java:8565)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1344)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4733)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4983)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:123)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3059)
at android.os.Handler.dispatchMessage(Handler.java:117)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:293)
at android.app.ActivityThread.loopProcess(ActivityThread.java:9934)
at android.app.ActivityThread.main(ActivityThread.java:9923)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1240)
生成的布局文件代码如下 :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
<fragment
android:id="@+id/nav_host_fragment_activity_bottom_navigation"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
生成的主界面代码如下 :
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import cn.zkhw.client.databinding.ActivityBottomNavigationBinding
class BottomNavigationActivity : AppCompatActivity() {
private lateinit var binding: ActivityBottomNavigationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBottomNavigationBinding.inflate(layoutInflater)
setContentView(binding.root)
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_bottom_navigation)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
报错的代码是
setupActionBarWithNavController(navController, appBarConfiguration)
报错信息 :
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
at androidx.navigation.ui.ActionBarOnDestinationChangedListener.setTitle(ActionBarOnDestinationChangedListener.java:48)
at androidx.navigation.ui.AbstractAppBarOnDestinationChangedListener.onDestinationChanged(AbstractAppBarOnDestinationChangedListener.java:103)
at androidx.navigation.NavController.addOnDestinationChangedListener(NavController.java:233)
at androidx.navigation.ui.NavigationUI.setupActionBarWithNavController(NavigationUI.java:227)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)
at cn.zkhw.client.BottomNavigationActivity.onCreate(BottomNavigationActivity.kt:32)
分析上述报错信息 , 可以得知 , 尝试调用 androidx.appcompat.app.ActionBar 的 void setTitle() 方法 , 但是 androidx.appcompat.app.ActionBar 对象是空的 , 直接报空指针异常 ;
进入 setupActionBarWithNavController(navController, appBarConfiguration)
方法中 , 分析其代码 :
fun AppCompatActivity.setupActionBarWithNavController(
navController: NavController,
configuration: AppBarConfiguration = AppBarConfiguration(navController.graph)
) {
NavigationUI.setupActionBarWithNavController(this, navController, configuration)
}
在上述代码中调用了 NavigationUI.setupActionBarWithNavController() 方法 , 这是 Navigation 中的常用方法 , 用于将 NavigationView 和 NavigationController 和 ActionBar 关联起来 ;
此处没有获取到 ActionBar 对象 , ActionBar 是页面顶部的 标题栏 ;
在 Android Studio 中生成的代码 , 一般都是标准代码 , 不会出错 , 这里出现问题大概率是自己在项目中的其它设置导致的 ;
检查 AndroidManifest.xml 中的 Theme 主题设置 , 在 application 标签中 , 设置了 Theme.AppCompat.Light.NoActionBar 标题 , 这就是此时的报错原因 ,
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:usesCleartextTraffic="true">
设置了 Theme.AppCompat.Light.NoActionBar 主题 , 肯定是没有 ActionBar 的 , 因此这里尝试调用 androidx.appcompat.app.ActionBar 的 setTitle() 方法直接报空指针异常 ;
为报错的 Activity 单独配置一个
Theme.AppCompat.Light.DarkActionBar
主题 , 这样该 Activity 就会有 ActionBar , 就不会报错了 ;
<activity
android:name=".NavigationActivity"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:label="@string/title_activity_bottom_navigation"></activity>
执行效果如下图所示 :
在上述代码中 , 调用了 NavigationUI.setupActionBarWithNavController 函数 , 关联了 Navigation 与 ActionBar , 这里可以调用其他的关联方法 ,
调用 NavigationUI.setupWithNavController() 方法 , 可以只关联 NavigationView 与 NavigationController , 不需要关联 ActionBar ,
此外 上述代码 与 navView.setupWithNavController(navController) 效果相同 , 这里可以注释掉 setupActionBarWithNavController(navController, appBarConfiguration)
代码 , 此时就不会因为找到 ActionBar 而报空指针异常 ;
注释掉上述代码后 , 效果如下 :
class BottomNavigationActivity : AppCompatActivity() {
private lateinit var binding: ActivityBottomNavigationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBottomNavigationBinding.inflate(layoutInflater)
setContentView(binding.root)
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_bottom_navigation)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
//setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
运行效果如下 :