Android onCreateOptionsMenu вызывается дважды при изменении ориентации

Я играю с жизненным циклом Android и обнаружил, что поведение плохо документировано (или я просто делаю что-то не так).

Метод onCreateOptionsMenu, как указано на https://developer.android.com/reference/android/app/Activity.html, должен вызываться только один раз, но он печатается дважды во время смены ориентации.

Ниже приведен журнал потока создания, поскольку вы можете видеть, что метод onCreateOptionsMenu вызывается сразу после метода onPostResume:

 [...]
 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
 [...]

Но когда состояние восстанавливается из-за изменения ориентации, оно также вызывается после метода onRestoreInstanceState:

 [...]
 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
 [...]

Стоит отметить, что это происходит только в API > 19 без библиотеки поддержки.

Код, используемый для регистрации, довольно прост. SimpleActivity настраивает представление содержимого и добавляет экземпляр SimpleFragment в FragmentManager (если он еще не был добавлен):

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;
  }
}

LoggerActivity и LoggerFragment реализуют все методы жизненного цикла и вызывают Utils.logBeforeSuper и Utils.logAfterSuper для каждого метода.

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;
  }

  /* [...] */
}

Итак, я хотел бы знать, каково ожидаемое поведение? Я что-то упустил или это не задокументировано?

Некоторые ссылки

Полный файл журнала можно найти здесь (поток изменения ориентации начинается со строки 108): https://docs.google.com/spreadsheets/d/1u97W9QZIEDcJt1Q2xh5VQP4YliHjzHE0u2OlLF4y5WY/edit

Проект размещен на github: (у меня недостаточно репутации, чтобы добавить больше ссылок)

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

0 ответов

Другие вопросы по тегам