I'm playing with the Android lifecycle and I found a behavior that seems to have been poorly documented (or I'm just doing something wrong).
The onCreateOptionsMenu method, as specified at https://developer.android.com/reference/android/app/Activity.html#onCreateOptionsMenu(android.view.Menu), is supposed to be called only once, but it is being printed twice during the orientation change.
The following is the creation flow log, as you can see the onCreateOptionsMenu method is called right after onPostResume method:
[...]
SimpleActivity >>> onStart
SimpleActivity <<< onStart
SimpleFragment >>> onStart
SimpleFragment <<< onStart
SimpleActivity >>> onPostCreate
SimpleActivity <<< onPostCreate
SimpleActivity >>> onResume
SimpleActivity <<< onResume
SimpleFragment >>> onResume
SimpleFragment <<< onResume
SimpleActivity >>> onPostResume
SimpleActivity <<< onPostResume
SimpleActivity >>> onCreateOptionsMenu
SimpleActivity <<< onCreateOptionsMenu
SimpleFragment >>> onCreateOptionsMenu
SimpleFragment <<< onCreateOptionsMenu
[...]
But when the state is being restored due to an orientation change, it is called after onRestoreInstanceState method too:
[...]
SimpleActivity >>> onStart
SimpleActivity <<< onStart
SimpleFragment >>> onStart
SimpleFragment <<< onStart
SimpleActivity >>> onRestoreInstanceState
SimpleActivity >>> onCreateOptionsMenu
SimpleActivity <<< onCreateOptionsMenu
SimpleFragment >>> onCreateOptionsMenu
SimpleFragment <<< onCreateOptionsMenu
SimpleActivity >>> onPrepareOptionsMenu
[...]
SimpleActivity <<< onRestoreInstanceState
SimpleActivity >>> onPostCreate
SimpleActivity <<< onPostCreate
SimpleActivity >>> onResume
SimpleActivity <<< onResume
SimpleFragment >>> onResume
SimpleFragment <<< onResume
SimpleActivity >>> onPostResume
SimpleActivity <<< onPostResume
SimpleActivity >>> onCreateOptionsMenu
SimpleActivity <<< onCreateOptionsMenu
SimpleFragment >>> onCreateOptionsMenu
SimpleFragment <<< onCreateOptionsMenu
[...]
It's worth noting that this behavior only occurs in API > 19 without the Support library.
The code used to log is pretty simple. The SimpleActivity configures the content view and adds an instance of SimpleFragment to the FragmentManager (if it wasn't added yet):
public class SimpleActivity extends LoggerActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
Fragment f = getFragmentManager().findFragmentById(R.id.fragment_container);
findViewById(R.id.btn_dialog).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
startActivity(new Intent(SimpleActivity.this, DialogActivity.class));
}
});
findViewById(R.id.btn_activity).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
startActivityForResult(new Intent(SimpleActivity.this, ResultActivity.class), Utils.REQUEST_CODE);
}
});
if (f == null) {
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new SimpleFragment())
.commit();
}
}
}
//////
public class SimpleFragment extends LoggerFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_layout, container, false);
TextView txt = (TextView) v.findViewById(R.id.fragment_text);
txt.setText(this instanceof CustomName ? ((CustomName) this).getCustomName() : getClass().getSimpleName());
return v;
}
}
The LoggerActivity and LoggerFragment implements all the lifecycle methods and calls Utils.logBeforeSuper and Utils.logAfterSuper on each method.
public class LoggerActivity extends Activity {
/* [...] */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
Utils.logBeforeSuper(this);
boolean b = super.onCreateOptionsMenu(menu);
Utils.logAfterSuper(this);
return b;
}
/* [...] */
}
public class LoggerFragment extends Fragment {
/* [...] */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Utils.logBeforeSuper(this);
View v = super.onCreateView(inflater, container, savedInstanceState);
Utils.logAfterSuper(this);
return v;
}
/* [...] */
}
So, I would like to know what's the expected behavior? Am I missing something or it is not documented?
Some links
The full log file could be found here (The orientation change flow starts at line 108): https://docs.google.com/spreadsheets/d/1u97W9QZIEDcJt1Q2xh5VQP4YliHjzHE0u2OlLF4y5WY/edit#gid=0
The project is hosted on github: (I don't have enough reputation to add more links)
Whole Project: https://github.com/TartagliaEG/android-lifecycle-tests
LoggerActivity: /app/src/main/java/com/lifecycletests/base/loggers/LoggerActivity.java
LoggerFragment: /app/src/main/java/com/lifecycletests/base/loggers/LoggerFragment.java
Utils: /app/src/main/java/com/lifecycletests/utils/Utils.java
SimpleActivity: /app/src/main/java/com/lifecycletests/simple/SimpleActivity.java
SimpleFragment: /app/src/main/java/com/lifecycletests/simple/SimpleFragment.java