2

I'm trying to make the last MenuItem invisible in the Drawer menu. Despite the existing solutions on Stackoverflow I get a null pointer exception and don't understand it.

navdrawer_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/faq_id"
        android:icon="@drawable/contact_support_24px"
        android:title="@string/frequently_asked_questions" />
    <item
        android:id="@+id/support_id"
        android:icon="@drawable/email_24px"
        android:title="@string/support_suggestions" />
    <item
        android:id="@+id/news_twitter_id"
        android:icon="@drawable/twitter"
        android:title="@string/news_twitter" />
    <item
        android:id="@+id/news_facebook_id"
        android:icon="@drawable/facebook_24px"
        android:title="@string/news_facebook" />
    <item
        android:id="@+id/signout_id"
        android:icon="@drawable/logout"
        android:title="@string/sign_out" />
</menu>

Activity layout:

<layout>
    <androidx.drawerlayout.widget.DrawerLayout
        <LinearLayout
            <fragment/>
        </LinearLayout>

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navViewVpn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/nav_header"
            app:menu="@menu/navdrawer_menu" />
    </androidx.drawerlayout.widget.DrawerLayout>
</layout>

Activity Code:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val navView: NavigationView = findViewById(R.id.navViewVpn)
        val i = navView.headerCount // 1
        val header: View = navView.getHeaderView(0)
        val signout: MenuItem = header.findViewById(R.id.signout_id) // Crash
}

The crash is on the last line, it can't even find the signout_id under the header. But why?

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.company.App.vpn.android, PID: 12008
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company.App.vpn.android/com.company.App.vpn.android.VpnActivity}: java.lang.NullPointerException: header.findViewById(R.id.signout_id) must not be null
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException: header.findViewById(R.id.signout_id) must not be null
Houman
  • 64,245
  • 87
  • 278
  • 460

1 Answers1

0

In this line, we are trying to assign a View instance to a variable of type MenuItem. MenuItem does not extend View (and therefore doesn't exist), so this assignment is giving us some trouble.

val signout: MenuItem = header.findViewById(R.id.signout_id)

Grabbing that MenuItem is absolutely on the right track. However, the header element is actually a separate element of the navigation drawer and not useful in this case. Instead, we can get a reference to the MenuItem using the navView instance. Then, use the findItem method, as opposed to findViewById.

From there one can programmatically edit the menu item as necessary.

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val navView: NavigationView = findViewById(R.id.navViewVpn)

        val signout: MenuItem = navView.menu.findItem(R.id.signout_id);
        
        // Edit the menu item as required
        signout.isVisible = false;
}

Note, for anyone doing this in Java, the equivalent code is as follows.

NavigationView navView = findViewById(R.id.nav_view_id);
MenuItem item = navView.getMenu().findItem(R.id.navItemId);