Программно вернуться к предыдущему фрагменту в стопке

Скажем, что у меня есть активность, которая имеет фрагменты, добавленные программно:

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() просто закрывает активность, которая меня не интересует.

Есть ли лучший способ сделать это?

Ответ 2

Чтобы рассказать о других полученных ответах, это мое решение (помещено в действие):

@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();  
    }
}

Ответ 3

Когда мы обновляем/добавляем фрагменты,

Должен включать .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, если мы добавим/обновим фрагменты и вернемся к текущему экрану.

Ответ 4

replace() делает 2 вещи:

  • Удалить добавленный фрагмент (A) из контейнера (C), который вы указали
  • Добавить новый фрагмент (B) в тот же контейнер

Эти 2 операции - это то, что сохраняется как запись/транзакция Backstack. Обратите внимание, что фрагмент A остается в состоянии created, и его представление уничтожено.

Теперь popBackStack() отменяет вашу последнюю транзакцию, добавленную в BackStack.

В этом случае это будет 2 шага:

  • Удалить B из C
  • Добавить A в C

После этого фрагмент 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();

Ответ 5

Добавьте эти строки в метод onBackPressed(). Метод popBackStackImmediate() вернет вас к предыдущему фрагменту, если у вас есть фрагмент в стеке `

if(getFragmentManager().getBackStackEntryCount() > 0){
     getFragmentManager().popBackStackImmediate();
}
else{
    super.onBackPressed();
}

`

Ответ 6

Это решение идеально подходит для навигации по фрагментам в нижней строке, когда вы хотите закрыть приложение при обратном нажатии в основном фрагменте.

С другой стороны, когда вы открываете вторичный фрагмент (фрагмент во фрагменте), который в моем коде определен как "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();

Ответ 7

Программно вернуться к предыдущему фрагменту, используя следующий код.

if ( getFragmentManager().getBackStackEntryCount() > 0) 
{
          getFragmentManager().popBackStack();
          return;
}
super.onBackPressed();

Ответ 8

Чтобы этот фрагмент появился снова, просто добавьте этот фрагмент в 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.

Удачного кодирования!

Ответ 9

Добавив 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();
        }
    });

Ответ 10

Попробуйте код ниже:

@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();
            }
        }
    }

Ответ 11

Эти ответы не работают, если у меня нет addToBackStack(), добавленной к моей транзакции фрагмента, но вы можете использовать:

getActivity().onBackPressed();

из любого фрагмента вернуться на один шаг назад;