0

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
TartagliaEG
  • 11
  • 1
  • 4
  • some stuffs and code are called twice and i dont know why it happens like if you have spinner the onselect event will be fired during load... hence i always use a variable named "isLoaded" which i intialize in this place to know that first load event is fired and now anything next will be users:- onItemSelected() { if(isLoaded) { // do stuffs... } else isLoaded = true; } isLoaded = A flag which can be used to know if the activity is loaded There could be other reason or solution but this is what i use :) hope it helps u – Ahmad Feb 27 '17 at 18:52
  • I don't really have a problem with it being called twice, I'm just trying to figure out what's the expected behavior. But the flag would probably be a good solution for those facing it as a problem. – TartagliaEG Feb 27 '17 at 19:00

0 Answers0