带有(架构导航组件)和 BottomNavigationView 的初始屏幕

Dr *_*ido 1 android splash-screen android-theme kotlin android-databinding

我试图在包含BottomNavigationView三个片段的应用程序中实现启动屏幕,并且我使用了最著名的方法,例如在不创建新活动或片段的情况下执行此操作的答案,但在直接启动启动屏幕后出现问题,它得到“RuntimeException”和空指针异常”

\n
E/AndroidRuntime: FATAL EXCEPTION: main\n    Process: com.mml.foody, PID: 6868\n    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\n        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)\n        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)\n        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)\n        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)\n        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)\n        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)\n        at android.os.Handler.dispatchMessage(Handler.java:106)\n        at android.os.Looper.loop(Looper.java:223)\n        at android.app.ActivityThread.main(ActivityThread.java:7656)\n        at java.lang.reflect.Method.invoke(Native Method)\n        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)\n        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)\n     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method \'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)\' on a null object reference\n        at androidx.navigation.ui.ActionBarOnDestinationChangedListener.setTitle(ActionBarOnDestinationChangedListener.java:48)\n        at androidx.navigation.ui.AbstractAppBarOnDestinationChangedListener.onDestinationChanged(AbstractAppBarOnDestinationChangedListener.java:103)\n        at androidx.navigation.NavController.addOnDestinationChangedListener(NavController.java:233)\n        at androidx.navigation.ui.NavigationUI.setupActionBarWithNavController(NavigationUI.java:237)\n        at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)\n        at com.mml.foody.ui.MainActivity.onCreate(MainActivity.kt:39)\n        at android.app.Activity.performCreate(Activity.java:8000)\n        at android.app.Activity.performCreate(Activity.java:7984)\n        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)\n        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)\n        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)\xc2\xa0\n        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)\xc2\xa0\n        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)\xc2\xa0\n        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)\xc2\xa0\n        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)\xc2\xa0\n        at android.os.Handler.dispatchMessage(Handler.java:106)\xc2\xa0\n        at android.os.Looper.loop(Looper.java:223)\xc2\xa0\n        at android.app.ActivityThread.main(ActivityThread.java:7656)\xc2\xa0\n        at java.lang.reflect.Method.invoke(Native Method)\xc2\xa0\n        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)\xc2\xa0\n        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)\xc2\xa0\nI/Process: Sending signal. PID: 6868 SIG: 9\n
Run Code Online (Sandbox Code Playgroud)\n

样式

\n
<style name="SplashScreenStyle" parent="Theme.MaterialComponents.DayNight.NoActionBar">\n        <item name="android:windowBackground">@drawable/splash_screen</item>\n    </style>\n
Run Code Online (Sandbox Code Playgroud)\n

AndroidManifest.xml

\n
<manifest xmlns:android="http://schemas.android.com/apk/res/android"\n    package="com.mml.foody">\n\n    <uses-permission android:name="android.permission.INTERNET" />\n    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\n\n    <application\n        android:name=".MyApplication"\n        android:allowBackup="true"\n        android:fullBackupContent="true"\n        android:icon="@mipmap/ic_launcher"\n        android:label="@string/app_name"\n        android:roundIcon="@mipmap/ic_launcher_round"\n        android:supportsRtl="true"\n        android:theme="@style/SplashScreenStyle"\n        android:usesCleartextTraffic="true">\n        <activity\n            android:name=".ui.DetailsActivity"\n            android:label="Details"\n            android:theme="@style/DetailsActivityStyle">\n\n        </activity>\n        <activity android:name=".ui.MainActivity">\n            <intent-filter>\n                <action android:name="android.intent.action.MAIN" />\n\n                <category android:name="android.intent.category.LAUNCHER" />\n            </intent-filter>\n        </activity>\n\n        <meta-data\n            android:name="preloaded_fonts"\n            android:resource="@array/preloaded_fonts" />\n    </application>\n\n</manifest>\n
Run Code Online (Sandbox Code Playgroud)\n

活动主文件

\n
<?xml version="1.0" encoding="utf-8"?>\n<layout xmlns:android="http://schemas.android.com/apk/res/android"\n    xmlns:app="http://schemas.android.com/apk/res-auto"\n    xmlns:tools="http://schemas.android.com/tools">\n\n    <data>\n\n    </data>\n\n    <LinearLayout\n        android:layout_width="match_parent"\n        android:layout_height="match_parent"\n        android:background="@color/lightGray"\n        android:orientation="vertical"\n        tools:context=".ui.MainActivity">\n\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id="@+id/nav_host_fragment_container"\n            android:name="androidx.navigation.fragment.NavHostFragment"\n            android:layout_width="match_parent"\n            android:layout_height="0dp"\n            android:layout_weight="2"\n            app:defaultNavHost="true"\n            app:navGraph="@navigation/nav_graph" />\n\n        <com.google.android.material.bottomnavigation.BottomNavigationView\n            android:id="@+id/bottomNavigationView"\n            android:layout_width="match_parent"\n            android:layout_height="wrap_content"\n            app:menu="@menu/bottom_nav_menu" />\n\n    </LinearLayout>\n</layout>\n
Run Code Online (Sandbox Code Playgroud)\n

主要活动类

\n
class MainActivity : AppCompatActivity() {\n\n    private lateinit var binding:ActivityMainBinding\n    private lateinit var navHostFragment: NavHostFragment\n    private lateinit var navController: NavController\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        setTheme(R.style.SplashScreenStyle)\n        super.onCreate(savedInstanceState)\n        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)\n        setContentView(binding.root)\n\n\n        navHostFragment =\n            supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment\n\n        navController = navHostFragment.navController\n\n        val appBarConfiguration = AppBarConfiguration(\n            setOf(R.id.recipesFragment, R.id.favoriteRecipesFragment, R.id.foodJokeFragment)\n        )\n\n        binding.bottomNavigationView.setupWithNavController(navController)\n        setupActionBarWithNavController(navController,appBarConfiguration)\n\n\n\n    }\n\n    override fun onSupportNavigateUp(): Boolean {\n        return navController.navigateUp() ||  super.onSupportNavigateUp()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\n

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

\n
<?xml version="1.0" encoding="utf-8"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"\n    xmlns:app="http://schemas.android.com/apk/res-auto"\n    xmlns:tools="http://schemas.android.com/tools"\n    android:layout_width="match_parent"\n    android:layout_height="match_parent"\n    android:background="@color/lightGray"\n    tools:context=".ui.MainActivity">\n\n    <fragment\n        android:id="@+id/navHostFragment"\n        android:name="androidx.navigation.fragment.NavHostFragment"\n        android:layout_width="0dp"\n        android:layout_height="0dp"\n        app:defaultNavHost="true"\n        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"\n        app:layout_constraintEnd_toEndOf="parent"\n        app:layout_constraintStart_toStartOf="parent"\n        app:layout_constraintTop_toTopOf="parent"\n        app:navGraph="@navigation/my_nav" />\n\n    <com.google.android.material.bottomnavigation.BottomNavigationView\n        android:id="@+id/bottomNavigationView"\n        android:layout_width="0dp"\n        android:layout_height="wrap_content"\n        app:layout_constraintBottom_toBottomOf="parent"\n        app:layout_constraintEnd_toEndOf="parent"\n        app:layout_constraintHorizontal_bias="0.5"\n        app:layout_constraintStart_toStartOf="parent"\n        app:menu="@menu/bottom_nav_menu"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n
Run Code Online (Sandbox Code Playgroud)\n

\n

MML*_*MML 6

如果您想要一个包含操作栏或底部导航视图的应用程序启动屏幕,您应该创建一个单独的活动或片段,我更喜欢使用片段来做到这一点,因为它比活动轻量级且性能最佳

  1. 创建一个像这样的 Splash 片段
<?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>
Run Code Online (Sandbox Code Playgroud)
  1. 在 navGraph 中将 SplashFragment 的操作添加到您的 Home fragment
<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>
Run Code Online (Sandbox Code Playgroud)

有了这三个属性,当单击后退按钮时,应用程序将退出而不返回到启动片段

app:launchSingleTop="true"
app:popUpTo="@id/splashScreenFragment"
app:popUpToInclusive="true" />
Run Code Online (Sandbox Code Playgroud)
  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())
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  navController.addOnDestinationChangedListener { _, destination, _ ->
            if(destination.id == R.id.splashScreenFragment) {

                binding.bottomNavigationView.visibility = View.GONE
            } else {

                binding.bottomNavigationView.visibility = View.VISIBLE
            }
        }
Run Code Online (Sandbox Code Playgroud)