Какой метод вызывается после popBackStack?
У меня есть активность, где я вызываю три фрагмента - каждый зависит друг от друга:
A (ctivity) → f1 (Fragment one, title {is | should}: list) → f2 (фрагмент two, title {is | should}: обзор) → f3 (фрагмент три, название {is | должен}: подробно)
ATM Я использую следующий вызов метода для перехода назад:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount()>0){
fragmentManager.popBackStack();
}
}
}
Это прекрасно работает.
Я переопределяю заголовок ActionBar в каждом фрагменте следующим образом:
ActionBar bar = getSherlockActivity().getSupportActionBar();
bar.setTitle(R.string.title_f3);
При навигации вперед (как показано выше) это работает безупречно, но при навигации назад название ActionBar не обновляется:
f3 (title {is | should}: detail) → f2 (title {is}: detail, {should}: overview) → f1 (title {is}: detail, {should}: list)
Очевидно, я мог бы просто обновить его снова, когда будет показан фрагмент. Но мой отладчик никогда не останавливается ни на одном из методов, за исключением тех, которые будут называться как onResume().
Итак, существует ли какой-либо метод, который вызывается в предыдущем фрагменте после popBackStack()?
Ответы
Ответ 1
Я знаю, что это немного поздно для ответа, но для тех, кто идет сюда, это может помочь!
Первое, что нужно сделать первым: popBackStack() не создает фрагмент, он выдает транзакцию фрагмента. Таким образом, последняя транзакция фрагмента отменяется при вызове. Если вы сейчас показывали FragmentA, и ваша транзакция была:
fragmentTransaction.replace(R.id.your_layout, fragmentB);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Он заменит FragmentA на FragmentB и добавит эту транзакцию (а не фрагмент) в задний стек. Если вы затем нажмете кнопку "Назад", она выведет транзакцию с заднего стека, которая "заменила этот фрагмент A на FragmentB". По сути, эта инструкция отменяет последнюю транзакцию и удаляет ее из стека выполненных транзакций. Если исходный FragmentA все еще существует, он использует его. Если он был уничтожен, он создает новый.
Итак, если фрагмент не был уничтожен, то, напомнив фрагмент после использования в popBackStack(), вызывается методы onStart() и onResume(). Если фрагмент был ранее уничтожен, тогда будут вызваны методы жизненного цикла, начиная с onAttach(). Он аналогичен нажатию кнопки "Назад" в разделе "Действия".
Теперь важный бит, что происходит при повторном жизненном цикле фрагмента, когда мы выходим обратно в стек? Ну, как сказано перед транзакцией фрагмента, так:
Сценарий 1: ваш фрагментB еще не существовал до транзакции.
В этом случае вызовы onCreate() и onAttach() вызываются во время транзакции, поэтому фрагмент будет уничтожен и отсоединен, если вы вызовете popBackStack() и отмените транзакцию (примечание FragmentA, вероятно, уже существует, поэтому замена его не уничтожит его, не отменяя создание фрагмента). В этом случае методы жизненного цикла будут называться начиная с onAttach().
Сценарий 2: ваш фрагментB уже существовал до транзакции. В этом случае фрагмент не будет уничтожен, а при следующем доступе к нему вызывается методы onStart() и onResume().
![Жизненный цикл фрагмента]()
Этот человек здесь объясняет несколько вещей об использовании popbackstack() http://vinsol.com/blog/2014/09/19/transaction-backstack-and-its-management/ и жизненного цикла фрагмента http://vinsol.com/blog/2014/10/22/fragment-view-state-retention-a-dirty-solution/. Другие связанные должности тоже заслуживают внимания!
Ответ 2
Мое обходное решение - получить текущее название панели действий в Фрагменте, прежде чем устанавливать его в новый заголовок. Таким образом, после того, как появится фрагмент, я могу вернуться к этому заголовку.
@Override
public void onResume() {
super.onResume();
// Get/Backup current title
mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
.getTitle();
// Set new title
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(R.string.this_fragment_title);
}
@Override
public void onDestroy() {
// Set title back
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(mTitle);
super.onDestroy();
}
Ответ 3
используйте метод addOnBackStackChangedListener в вашем BaseActivity, который будет вызываться в любой момент времени назад
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager fm = getSupportFragmentManager();
if (fm != null) {
int backStackCount = fm.getBackStackEntryCount();
if (backStackCount == 0) {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
}
setToolbarTittle(R.string.app_name);
} else {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.back);
}
}
}
}
});
Ответ 4
Я использую следующее обходное решение:
1) установите 1-й фрагмент setHasOptionsMenu(false)
, прежде чем добавить второй фрагмент поверх 1-го.
2) установите 1-й фрагмент setHasOptionsMenu(true)
в onOptionsItemSelected()
после возврата из второго фрагмента.
3) onCreateOptionsMenu()
первого фрагмента следует вызывать, и вы можете здесь изменить панель действий.
Но я хочу знать лучшее решение.
Ответ 5
Вы можете найти красивую диаграмму жизненного цикла Fragment
в андроидных документах здесь. Так что да, если фрагмент выведен на передний план из-под задней части onCreateView()
, onActivityCreated()
, onStart()
и onResume()
вызывается.