Ответ 1
Посмотрите на методы getFragmentManager().popBackStack()
(их можно выбрать несколько)
http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()
Скажем, что у меня есть активность, которая имеет фрагменты, добавленные программно:
private void animateToFragment(Fragment newFragment, String tag) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();
}
Каков наилучший способ вернуться к предыдущему фрагменту, который был видимым?
Я нашел функциональность кнопки "триггер" при нажатии кнопки в Android, но я думаю, что симуляция события "назад" не является правильным способом для этого ( и я не могу заставить его работать):
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
Вызов finish()
просто закрывает активность, которая меня не интересует.
Есть ли лучший способ сделать это?
Посмотрите на методы getFragmentManager().popBackStack()
(их можно выбрать несколько)
http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()
Чтобы рассказать о других полученных ответах, это мое решение (помещено в действие):
@Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
Когда мы обновляем/добавляем фрагменты,
Должен включать .addToBackStack()
.
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
.addToBackStack(null)
.commit();
После этого, если мы дадим getFragments.popBackStackImmediate()
, вернем true, если мы добавим/обновим фрагменты и вернемся к текущему экрану.
replace()
делает 2 вещи:
Эти 2 операции - это то, что сохраняется как запись/транзакция Backstack. Обратите внимание, что фрагмент A остается в состоянии created
, и его представление уничтожено.
Теперь popBackStack()
отменяет вашу последнюю транзакцию, добавленную в BackStack.
В этом случае это будет 2 шага:
После этого фрагмент B становится detached
, и если вы не сохранили ссылки на него, это будет собирать мусор.
Чтобы ответить на первую часть вашего вопроса, нет вызова onCreate()
, потому что FragmentB остался в состоянии created
. И ответ на вторую часть вопроса немного длиннее.
Во-первых, важно понимать, что вы фактически не добавляете Fragments
в Backstack, вы добавляете FragmentTransactions
. Поэтому, когда вы думаете, что вы "замените фрагментом B, добавив фрагмент A в задний стек", вы фактически добавите всю эту операцию в стопку - это замена A на B. Эта замена состоит из двух действий - удалите A и добавьте B.
Затем следующий шаг - это посылка транзакции, которая содержит эту замену. Таким образом, вы не выходите из FragmentA, вы меняете "удалить A, добавьте B", который обратный - "удалить B, добавить A".
И тогда последний шаг должен быть более ясным - нет B, о котором знает FragmentManager, поэтому, добавив его, заменив A на B на последнем шаге, B должен пройти его ранние методы жизненного цикла - onAttach()
и onCreate()
.
Нижеприведенный код иллюстрирует, что происходит.
FragmentManager fm = getFragmentManager();
FragmentA fragmentA = new FragmentA();
FragmentB fragmentB = new FragmentB();
// 1. Show A
fm.beginTransaction()
.add(fragmentA, R.id.container)
.commit();
// 2. Replace A with B
// FragmentManager keeps reference to fragmentA;
// it stays attached and created; fragmentB goes
// through lifecycle methods onAttach(), onCreate()
// and so on.
fm.beginTransaction()
.replace(fragmentB, R.id.container)
.addToBackstack(null)
.commit();
// 2'. Alternative to replace() method
fm.beginTransaction()
.remove(fragmentA)
.add(fragmentB, R.id.container)
.addToBackstack(null)
.commit();
// 3. Reverse (2); Result - A is visible
// What happens:
// 1) fragmentB is removed from container, it is detached now;
// FragmentManager doesn't keep reference to it anymore
// 2) Instance of FragmentA is placed back in the container
// Now your Backstack is empty, FragmentManager is aware only
// of FragmentA instance
fm.popBackStack();
// 4. Show B
// Since fragmentB was detached, it goes through its early
// lifecycle methods: onAttach() and onCreate().
fm.beginTransaction()
.replace(fragmentB, R.id.container)
.addToBackstack(null)
.commit();
Добавьте эти строки в метод onBackPressed(). Метод popBackStackImmediate() вернет вас к предыдущему фрагменту, если у вас есть фрагмент в стеке `
if(getFragmentManager().getBackStackEntryCount() > 0){
getFragmentManager().popBackStackImmediate();
}
else{
super.onBackPressed();
}
`
Это решение идеально подходит для навигации по фрагментам в нижней строке, когда вы хотите закрыть приложение при обратном нажатии в основном фрагменте.
С другой стороны, когда вы открываете вторичный фрагмент (фрагмент во фрагменте), который в моем коде определен как "DetailPizza", он вернет предыдущее состояние первичного фрагмента. Ура!
Внутри деятельности на спине нажмите это:
Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");
if (home instanceof FragmentDetailedPizza && home.isVisible()) {
if (getFragmentManager().getBackStackEntryCount() != 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
} else {
//Primary fragment
moveTaskToBack(true);
}
И запусти другой фрагмент так:
Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();
Программно вернуться к предыдущему фрагменту, используя следующий код.
if ( getFragmentManager().getBackStackEntryCount() > 0)
{
getFragmentManager().popBackStack();
return;
}
super.onBackPressed();
Чтобы этот фрагмент появился снова, просто добавьте этот фрагмент в backstack, который вы хотите вернуть обратно нажатием, например:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Fragment fragment = new LoginFragment();
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack("SignupFragment");
ft.commit();
}
}
});
В вышеупомянутом случае я открываю LoginFragment
когда Button button
нажата, прямо сейчас пользователь находится в SignupFragment
. Таким образом, если addToBackStack(TAG)
, где TAG = "SignupFragment"
, то при нажатии кнопки TAG = "SignupFragment"
в LoginFragment
мы возвращаемся к SignUpFragment
.
Удачного кодирования!
Добавив fragment_tran.addToBackStack(null)
в последний фрагмент, я могу вернуться к последнему фрагменту.
добавление нового фрагмента:
view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, new ChangePassword());
transaction.addToBackStack(null);
transaction.commit();
}
});
Попробуйте код ниже:
@Override
public void onBackPressed() {
Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if (myFragment != null && myFragment instanceof StepOneFragment) {
finish();
} else {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
Эти ответы не работают, если у меня нет addToBackStack(), добавленной к моей транзакции фрагмента, но вы можете использовать:
getActivity().onBackPressed();
из любого фрагмента вернуться на один шаг назад;