【问题标题】:Splash screen with (Architecture Navigation Components) and BottomNavigationView带有(架构导航组件)和 BottomNavigationView 的启动画面
【发布时间】:2023-03-29 07:31:02
【问题描述】:

我试图在我的应用程序中实现启动画面,其中包含三个片段的BottomNavigationView,我使用了最知名的方法,比如answer,在没有创建新的活动或片段的情况下做到这一点,但是在午餐启动后出现了问题直接屏幕,它得到“RuntimeException and NullPointerException”

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.mml.foody, PID: 6868
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mml.foody/com.mml.foody.ui.MainActivity}: 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:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     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:237)
        at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)
        at com.mml.foody.ui.MainActivity.onCreate(MainActivity.kt:39)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
I/Process: Sending signal. PID: 6868 SIG: 9

风格

<style name="SplashScreenStyle" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <item name="android:windowBackground">@drawable/splash_screen</item>
    </style>

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mml.foody">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/SplashScreenStyle"
        android:usesCleartextTraffic="true">
        <activity
            android:name=".ui.DetailsActivity"
            android:label="Details"
            android:theme="@style/DetailsActivityStyle">

        </activity>
        <activity android:name=".ui.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/lightGray"
        android:orientation="vertical"
        tools:context=".ui.MainActivity">


        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/nav_host_fragment_container"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottomNavigationView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:menu="@menu/bottom_nav_menu" />

    </LinearLayout>
</layout>

MainActivity 类

class MainActivity : AppCompatActivity() {

    private lateinit var binding:ActivityMainBinding
    private lateinit var navHostFragment: NavHostFragment
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(R.style.SplashScreenStyle)
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        setContentView(binding.root)


        navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment

        navController = navHostFragment.navController

        val appBarConfiguration = AppBarConfiguration(
            setOf(R.id.recipesFragment, R.id.favoriteRecipesFragment, R.id.foodJokeFragment)
        )

        binding.bottomNavigationView.setupWithNavController(navController)
        setupActionBarWithNavController(navController,appBarConfiguration)



    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() ||  super.onSupportNavigateUp()
    }
}

在谷歌搜索这个异常后,我看到了这个answer,我意识到这个错误是因为我在初始屏幕中使用了NoActionBar,并且还使用了这个导航组件setupActionBarWithNavController(navController,appBarConfiguration) 但我有这个应用程序的旧版本,具有相同的结构和代码,除了它与plugin: 'kotlin-android-extensions' 一起工作的一件事之外的所有内容,但我在 main_activity.xml 中使用了数据绑定并且它工作正常,那么我错过了什么或者如何解决这个问题不创建新的活动/片段?

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/lightGray"
    tools:context=".ui.MainActivity">

    <fragment
        android:id="@+id/navHostFragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/my_nav" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/bottom_nav_menu"/>

</androidx.constraintlayout.widget.ConstraintLayout>

【问题讨论】:

    标签: android kotlin splash-screen android-databinding android-theme


    【解决方案1】:

    如果您想要一个带有包含操作栏或底部导航视图的应用程序的初始屏幕,您应该创建一个单独的活动或片段,我更喜欢使用片段来执行此操作,因为它比活动轻量级和最佳性能

    1. 像这样创建一个 Splash Fragment
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/splash_screen"
        tools:context=".ui.fragments.SplashScreenFragment">
    </FrameLayout>
    
    1. 在 navGraph 中,将 SplashFragment 中的操作添加到您的主页片段
    <fragment
            android:id="@+id/splashScreenFragment"
            android:name="com.mml.foody.ui.fragments.SplashScreenFragment"
            tools:layout="@layout/fragment_splash_screen">
            <action
                android:id="@+id/action_splashScreenFragment_to_yourHomeFragment"
                app:destination="@id/yourHomeFragment"
                app:launchSingleTop="true"
                app:popUpTo="@id/splashScreenFragment"
                app:popUpToInclusive="true" />
        </fragment>
    

    这三个属性将被授予当点击返回按钮时应用程序退出而不是返回到启动片段

    app:launchSingleTop="true"
    app:popUpTo="@id/splashScreenFragment"
    app:popUpToInclusive="true" />
    
    1. 将此代码添加到SplashFragment 类 以仅在片段中隐藏操作栏
     override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            // Inflate the layout for this fragment
    
            (activity as AppCompatActivity?)!!.supportActionBar?.hide()
            return inflater.inflate(R.layout.fragment_splash_screen, container, false)
    
    
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            lifecycleScope.launchWhenCreated {
                goToRecipesFragment()
            }
    
        }
    
    
    
        override fun onDestroyView() {
            super.onDestroyView()
            (activity as AppCompatActivity?)!!.supportActionBar!!.show()
        }
    
        private suspend fun goToRecipesFragment() {
            delay(3000)
            findNavController()
                .navigate(SplashScreenFragmentDirections.actionSplashScreenFragmentToRecipesFragment())
        }
    }
    

    最后隐藏 bottomNavigationView 将此方法添加到 MainActivity

      navController.addOnDestinationChangedListener { _, destination, _ ->
                if(destination.id == R.id.splashScreenFragment) {
    
                    binding.bottomNavigationView.visibility = View.GONE
                } else {
    
                    binding.bottomNavigationView.visibility = View.VISIBLE
                }
            }
    

    【讨论】:

    • Mido 先生 -> 这似乎是一个更好的方法。感谢您的 MML
    【解决方案2】:

    问题发生在这里:setupActionBarWithNavController(navController,appBarConfiguration)。您正在设置一个不存在的 ActionBar 导致NullPointerException。更多信息请参考官方文档:Navigation Action Bar, Support Action Bar

    解决方案:(选择一项)
    1/ 如果您不需要 ActionBar 删除此行:
    setupActionBarWithNavController(navController,appBarConfiguration) 在 MainActivity 的 onCreate(...) 方法中

    2/ else为启动画面使用一个活动,并为其余活动创建一个样式。

    <style name="ActivitiesScreenStyle" parent="Theme.MaterialComponents.DayNight">
        <item name="android:windowBackground">@drawable/splash_screen</item>
    </style>
    

    在您的 android 清单中:

    <application
        ...
        android:theme="@style/ActivitiesScreenStyle"
        ...
        <activity android:name=".ui.YourSplashScreenActivity"
            android:theme="@style/SplashScreenStyle">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    

    这意味着您的 片段导航 发生在 YourSplashScreenActivity 之外的另一个活动上,否则您将再次收到相同的错误。
    干杯!

    【讨论】:

    • 这似乎可行,但是......在启动画面之后,丑陋的操作栏出现在下一个屏幕中,而不是默认的,我有这个应用程序的旧版本,具有相同的结构和setupActionBarWithNavController(navController,appBarConfiguration),它的工作原理好吧,我很困惑我不知道有什么不同,也许是一些旧的库
    • 您必须创建一个自定义工具栏/操作栏。有关如何创建它,请参阅此博客:medium.com/swlh/…。此外,为应用程序使用 .NoActionBar 主题。请接受我的回答,因为它解决了您的问题。
    • @a-david 不幸的是,这个问题的解决方案不完整,我尝试为主要片段创建一个自定义操作栏,但我又遇到了旧错误,别担心,我会为你 +1试着谢谢你
    • 很抱歉它没有完全帮助你,至少你现在知道问题的根源了。也感谢您的支持!
    【解决方案3】:

    尝试将 android:theme="@style/SplashScreenStyle"application 移动到

    <activity android:name=".ui.MainActivity"
        android:theme="@style/SplashScreenStyle">
    

    并在onCreateView 中设置AppTheme 因为看起来你正在使用

    setTheme(R.style.SplashScreenStyle)
    

    在你的MainActivity.kt

    Refer my code

    【讨论】:

    • 我试过这个并没有改变,我也在 MainActivity 中使用了这个 setTheme(R.style.SplashScreenStyle) 而不是在片段中
    • 我想说的是您在 MainActivity 中使用 setTheme(R.style.SplashScreenStyle),您需要为您的应用程序使用主题,例如 setTheme(R.style.MyDefaultLightTheme),因此由于资源不足而崩溃
    猜你喜欢
    • 2018-12-13
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    • 2019-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多