Search code examples
androidandroid-fragmentsandroid-actionbaractionbarsherlock

onCreateOptionsMenu called twice on configuration change


My app has two fragments, one a listing and one a detail view, which are both shown in landscape mode and only the listing is shown in portait. On configuration change, if I put a breakpoint in onCreateOptionsMenu of both fragments, they are being hit twice and the menu items in the Actionbar are being duplicated.

I tried setting invalidateOptionsMenu in different events, like onResume and onActivityCreated, but that doesn't seem to help. I'm not sure what would cause onCreateOptionsMenu to be hit twice.

I noticed there was a solution here, but that doesn't work for me. It causes a java.lang.IllegalArgumentException No view found for for fragment in onStart on the Activity.

UPDATE

I am using a ViewPager to load the fragments when in portait mode:

public class Main extends SherlockFragmentActivity
{
    private static List<Fragment> fragments;

    @Override
    public void onCreate(final Bundle icicle)
    {    
        setContentView(R.layout.main);
    }

    @Override
    public void onResume()
    { 
        mViewPager = (ViewPager)findViewById(R.id.viewpager);

               if (mViewPager != null)
               {

                  fragments = new ArrayList<Fragment>();

                  fragments.add(new MyListFragment());

                  fragments.add(MyDetailFragment.newInstance(0));
                  fragments.add(MyDetailFragment.newInstance(1));
                  fragments.add(MyDetailFragment.newInstance(2));

                  mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
                  mViewPager.setAdapter(mMyFragmentPagerAdapter);
               }
    }

    private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter  {  

        public MyFragmentPagerAdapter(FragmentManager fm) {  
             super(fm);  
        }  

        @Override  
        public Fragment getItem(int index) {
            return fragments.get(index);
        }  

        @Override
        public int getCount() {  
             return 4;  
        }

        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
   }
}

and it landscape mode I am adding the fragments via XML. This is the main.xml file in a layout-land folder:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    android:weightSum="3"
>
    <fragment android:name="com.app.ListingFragment"
            android:id="@+id/fragmentDetails"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
     />

    <fragment android:name="com.app.DetailFragment" 
            android:id="@+id/fragmentDetails"
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="fill_parent"
     />

</LinearLayout>

This is the XML in the layout folder:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
     />

 </RelativeLayout>

Solution

  • The problem is that you are adding the fragments on the layout file, and also instantiating them manually by calling the constructor/newInstance method.

    If you add a fragment on the layout, the android framework will instantiate it for you. In the code you posted, you are having 4 Details fragment and 2 list fragments instances total, even though you might not be able to see them all.

    Instead of instantiating the fragments manually, you should retrieve it's instance by calling FragmentManager.getFragmentById and use that instance instead.

    For the details fragments, instead of having one fragment declaration on the layout, i would replace it with a normal layout that you can use to add your pager adapter