I have a single activity app which uses a settings fragment (PreferenceFragmentCompat) with a custom layout (set via overriding the PreferenceThemeOverlay style). From the fragment's onViewCreated method I'm using setSupportActionBar to reference the toolbar which is present on that layout. This works fine until it runs on API 28+, at which point the reference to toolbarSettings is null and an error is raised.
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:104)
at androidx.navigation.NavController.addOnDestinationChangedListener(NavController.java:204)
at androidx.navigation.ui.NavigationUI.setupActionBarWithNavController(NavigationUI.java:228)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController$default(Activity.kt:89)
at com.simplenotes.notes.presentation.ui.SettingsFragment.setupActionBar(SettingsFragment.kt:39)
at com.simplenotes.notes.presentation.ui.SettingsFragment.onViewCreated(SettingsFragment.kt:20)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
I've seen mention of changes to custom preference fragments in this version however can't see anything specific to this behaviour. Does anyone know a solution or can point out what has been done wrong?
SettingsFragment.kt
class SettingsFragment : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupActionBar()
}
private fun setupActionBar() {
setHasOptionsMenu(true)
val hostActivity = requireActivity() as AppCompatActivity
hostActivity.setSupportActionBar(toolbarSettings)
hostActivity.setupActionBarWithNavController(findNavController())
val actionBar = hostActivity.supportActionBar
actionBar?.title = resources.getString(R.string.title_settings)
actionBar?.setDisplayHomeAsUpEnabled(true)
}
}
fragment_settings.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbarSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbarSettings"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
styles.xml
<resources>
<style name="Theme.MaterialComponents.DayNight.NoActionBar.Bridge" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge" />
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="preferenceTheme">@style/AppTheme.PreferenceThemeOverlay</item>
</style>
<style name="AppTheme.PreferenceThemeOverlay" parent="PreferenceThemeOverlay">
<item name="android:layout">@layout/fragment_settings</item>
</style>
</resources>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simplenotes.notes">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".presentation.ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Dependencies
implementation 'androidx.preference:preference:1.1.0'
implementation 'com.google.android.material:material:1.1.0'