Search code examples
javaandroidandroid-collapsingtoolbarlayoutscreen-rotation

App crashes on screen rotation when trying to find menu item


I am using a collapsingToolbarLayout in my application and as long as the menu is not collapsed there is no problem when rotating the phone. But when the menu is collapsed and only the original toolbar is showing the app crashes. The thing is, when only the original toolbar is showing a clickable item appears and disappears when the collapsing toolbar is shown. When rotating the phone, the application does not find this item. How can I solve this?

The activity where the menu is.

private Menu menu;
protected void onCreate(Bundle savedInstanceState) { 
    ...
    AppBarLayout mAppBarLayout = findViewById(R.id.appBarLayout2);
    mAppBarLayout.addOnOffsetChangedListener(new 
    AppBarLayout.OnOffsetChangedListener() {

            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int 
            verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {
                    isShow = true;
                    showOption();
                } else if (isShow) {
                    isShow = false;
                    hideOption();
                }
            }
        });

    }

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        this.menu = menu;
        getMenuInflater().inflate(R.menu.menu_scrolling, menu);
        hideOption();
        return true;
    }

private void hideOption() {
        MenuItem item = menu.findItem(R.id.action_info);
        item.setVisible(false);
    }

    private void showOption() {
        MenuItem item = menu.findItem(R.id.action_info);
        item.setVisible(true);
    }

The relevant code in xml-file:

<android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout2"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        android:theme="@style/AppTheme.Base"
        app:layout_constraintTop_toTopOf="@+id/nestedScrollView">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsTool"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorSecondary"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleGravity="bottom|center"
            app:expandedTitleMargin="16dp"
            app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Display2"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:title="@string/title_expenses">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:navigationIcon="@drawable/ic_action_exit"
                app:title="@string/title_expenses"
                app:titleTextColor="@android:color/background_light" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

The menu_Scrolling.xml

<menu 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"
    tools:context="com.journaldev.collapsingtoolbarlayout.ScrollingActivity">

    <item
        android:id="@+id/action_info"
        android:icon="@drawable/ic_action_add"
        android:orderInCategory="200"
        android:title="Add"
        app:showAsAction="ifRoom" />

</menu>

This is the error message:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.korneliapalm.android.samboappen/com.korneliapalm.android.samboappen.MoneyListActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
        at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
        at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7050)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
        at com.korneliapalm.android.samboappen.MoneyListActivity.showOption(MoneyListActivity.java:163)
        at com.korneliapalm.android.samboappen.MoneyListActivity.onCreate(MoneyListActivity.java:51)
        at android.app.Activity.performCreate(Activity.java:7327)
        at android.app.Activity.performCreate(Activity.java:7318)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257) 
        at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039) 
        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948) 
        at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7050) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965) 

Solution

  • The problem is that in onCreate you are calling the methods hideOption() and showOption(). However, oncreate is called before onCreateOptionsMenu which is where you are inflating the menu view. So calling menu.findItem(R.id.action_info); triggers a null pointer.

    getMenuInflater().inflate(R.menu.menu_scrolling, menu);
    

    You need to ensure that the menu view is inflated before you call these two methods in onCreate.

    private void hideOption() {
        if (menu == null) return;
        MenuItem item = menu.findItem(R.id.action_info);
        item.setVisible(false);
    }
    
    private void showOption() {
        if (menu == null) return;
        MenuItem item = menu.findItem(R.id.action_info);
        item.setVisible(true);
    }