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