Multiple menus showing in landscape mode


#1

I’ve noticed two odd things since I finished this chapter (with no issues), then moved on to the two-pane layout. Actually, I’m not sure exactly when the behavior I note below actually started, but I do know that after I finished chapter 18 I was not seeing it, and as I finished chapter 22 all of a sudden I noticed it was happening.

First, due to log entries I placed in CrimeListFragment in the onCreateView, onCreateContextMenu and onCreateOptionsMenu I see these methods getting called repeatedly when shifting to landscape and back to portrait mode. It seems that onCreateView increases by one, and onCreateOptionsMenu calls increase by two, each time I swap back and forth between portrait and landscape. This is so even though I do have retain instances set true:

[code] @Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, “onCreate called”);
super.onCreate(savedInstanceState);
// We have to let the Fragment Manager know that we want to create an options menu
setHasOptionsMenu(true);
// We retain the instance of the fragment in order that the ‘mSubtitleVisible’ variable
// survives rotation, so we know whether to show or hide the subtitle through a
// rotation
setRetainInstance(true);
mSubtitleVisible=false;

    getActivity().setTitle(R.string.crimes_title);
    mCrimes = CrimeLab.get(getActivity()).getCrimes();
    // Additional experimentation outside the chapter teaching - trying to keep 
    // track of the notion of a "selected row", even in touch mode:
    if ( savedInstanceState != null ) {
        if (savedInstanceState.containsKey(SELECTED_ROW)) {
            selectedRow = savedInstanceState.getInt(SELECTED_ROW);
        }
    }
    setListAdapter(new CrimeAdapter(mCrimes));

}

[/code]

Here is the log output:

INITIAL APP DISPLAY HERE:
01-13 21:08:34.957 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:34.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:35.047 7178-7178/com.reddragon.criminalintent D/libEGL﹕ loaded /system/lib/egl/libEGL_adreno200.so
01-13 21:08:35.057 7178-7178/com.reddragon.criminalintent D/libEGL﹕ loaded /system/lib/egl/libGLESv1_CM_adreno200.so
01-13 21:08:35.057 7178-7178/com.reddragon.criminalintent D/libEGL﹕ loaded /system/lib/egl/libGLESv2_adreno200.so
01-13 21:08:35.097 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:35.107 7178-7178/com.reddragon.criminalintent E/﹕ s3dReadConfigFile:75: Can’t open file for reading
01-13 21:08:35.107 7178-7178/com.reddragon.criminalintent E/﹕ s3dReadConfigFile:75: Can’t open file for reading

SWAP to LANDSCAPE HERE:
01-13 21:08:35.107 7178-7178/com.reddragon.criminalintent D/OpenGLRenderer﹕ Enabling debug mode 0
01-13 21:08:43.826 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:43.836 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:43.846 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:43.856 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:43.856 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:43.866 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

SWAP BACK TO PORTRAIT HERE:
01-13 21:08:43.896 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:46.369 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:46.379 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:46.379 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:46.389 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:46.389 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:46.389 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:46.399 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:46.399 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:46.399 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

SWAP TO LANDSCAPE HERE:
01-13 21:08:46.429 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:48.281 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:48.291 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:48.301 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:48.301 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:48.311 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.311 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.311 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.311 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.341 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.341 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.341 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:48.341 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

SWAP TO PORTRAIT HERE:
01-13 21:08:48.371 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:50.133 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:50.133 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:50.143 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:50.143 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:50.153 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:50.163 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.163 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.163 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.163 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.163 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.173 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.173 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.173 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.173 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:50.173 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

SWAP TO LANDSCAPE HERE:
01-13 21:08:50.193 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:53.927 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.927 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.937 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.937 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.947 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.947 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:53.957 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.957 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.967 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.967 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.967 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.967 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:53.977 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

AND THE LAST TIME BACK TO PORTRAIT HERE:
01-13 21:08:54.007 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.
01-13 21:08:56.109 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.119 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.119 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.129 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.129 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.139 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.149 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.170 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.180 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.180 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.190 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.190 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.190 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.190 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.190 7178-7178/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called
01-13 21:08:56.210 7178-7178/com.reddragon.criminalintent I/Adreno200-EGLSUB﹕ ConfigWindowMatch:2087: Format RGBA_8888.

Further, I notice that when switched to landscape mode, I have an extra (duplicate) ‘new’ menu item:

Also, I notice that the first time the app runs, the context menu in the upper right corner doesn’t show:

Then when I swap to landscape mode and back to portrait, I notice that the context menu shows, if I select the context menu I see that there are duplicate menu items now:

I’m not sure how to troubleshoot this - where to start looking?


#2

OK all, I think I answered my own question. Maybe there is a bug in the approach taken in the book, not quite sure, but I put log entries into the onCreate() method of SingleFragmentActivity, and I noticed that each time I switched from Portrait to Landscape, the onCreate() method would be called (which makes sense since the activity itself is destroyed and re-created). However, this code:

    FragmentManager fm = getFragmentManager();
    Fragment fragment =[b] fm.findFragmentById(getLayoutResId());[/b]
    if ( fragment == null ) {
        Log.i(TAG, "in onCreate adding a fragment with Id: " + getLayoutResId());
        fragment = createFragment();
        fm.beginTransaction()
               [b] .add(R.id.fragmentContainer, fragment)[/b]
                .commit();
    }

Turns out to be the culprit. I think. :neutral_face:

I believe the issue is that since the fragment is added to the fragment manager with the ID of the fragment container, but the search is done using the ID of the container layout, they will never match and thus the fragment search will always return null. This means that since a new fragment is constantly added, the onCreate will always be called on CrimeListFragment on a configuration change, which causes the options menu to have entries added to it each time.

I changed the code in SingleFragmentActivity to use tags instead, and now all seems correct:

[code] protected int getLayoutResId() {
return R.layout.activity_fragment;
}

protected String getLayoutResTag() {
    return String.valueOf(getLayoutResId());
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_fragment);

    FragmentManager fm = getFragmentManager();
    Fragment fragment = fm.findFragmentByTag(getLayoutResTag());
    if ( fragment == null ) {
        Log.i(TAG, "in onCreate adding a fragment with Tag: " + getLayoutResTag());
        fragment = createFragment();
        fm.beginTransaction()
                .add(R.id.fragmentContainer, fragment, getLayoutResTag())
                .commit();
    }

}

[/code]

Now here is the log output:

01-17 16:55:14.360 7969-7969/com.reddragon.criminalintent D/dalvikvm﹕ GC_FOR_ALLOC freed 154K, 2% free 9344K/9528K, paused 27ms, total 27ms
01-17 16:55:14.380 7969-7969/com.reddragon.criminalintent I/SingleFragmentActivity﹕ in onCreate adding a fragment with Tag: 2130903041
01-17 16:55:14.380 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreate called
01-17 16:55:14.380 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-17 16:55:14.420 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

CHANGE TO LANDSCAPE:
01-17 16:55:21.066 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-17 16:55:21.086 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called

CHANGE TO PORTRAIT:
01-17 16:55:27.452 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateView called
01-17 16:55:27.482 7969-7969/com.reddragon.criminalintent I/CrimeListFragment﹕ onCreateOptionsMenu called


#3

All -

OK, this issue actually turned out to be my own fault I think. In looking more closely at the code in the book, I noticed that in fact the sample used the same R.id for both the search and the transaction add - R.id.fragmentContainer.

FragmentManager fm = getFragmentManager(); Fragment fragment = fm.findFragmentById(R.id.fragmentContainer); if ( fragment == null ) { fragment = createFragment(); fm.beginTransaction() .add(R.id.fragmentContainer, fragment, getLayoutResTag()) .commit(); }

I think what happened is that I inadvertently changed the findFragmentId() call to use the new getLayoutResId() from the later chapter 22 on two-pane layouts. This of course would never match, and thus my menu problems started.

It was interesting to use the TAG approach, and see that this worked, but of course it was doing the same thing - registering it with one ID then testing for that same ID, so of course it worked.

Was good to actually cause me to really go step by step though through the various sequences of what calls what! Sorry for the false alarm.