PopBackStack, но сохраните первый фрагмент в Android

Я работаю над транзакцией фрагмента, и стопка выглядит так:

fragA => fragB => fragC => fragD

Я хотел бы вернуться к fragA после возвращения из fragD

fragD => onBackPress => fragA

Итак, я попробовал код вроде:

getChildFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

но он очищает весь задний стек, как я могу сохранить первый фрагмент в заднем стеке? Большое спасибо


person user782104    schedule 06.02.2015    source источник
comment
Этот ответ здесь: - stackoverflow.com/a/28115271/9969285 — самый простой и лучший обходной путь! В моем случае это работало с несколькими фрагментами (можно запускать в любом порядке после первого фрагмента), а нажатие назад всегда будет возвращаться к первому созданному фрагменту. Очень важно помнить, что не добавлять в стопку при создании первого фрагмента, а добавлять в стопку при добавлении всех остальных фрагментов.   -  person Jemshid    schedule 01.07.2018


Ответы (10)


Например. вы можете сделать следующее:

  • добавьте fragA, не добавляя его в backStack. Таким образом, он всегда будет
    активен и не будет реагировать на кнопку "Назад".
  • когда вы открываете fragD, вы должны очистить фрагмент BackStack. Поэтому, когда вы нажимаете кнопку «Назад» из фрагмента D, вы возвращаетесь к фрагменту A.

P.S. Есть и другие способы, как сделать то, что вы хотите. По-разному...

person Leonidos    schedule 06.02.2015
comment
Я очищаю весь backstack, затем снова добавляю fragA и fragD. Благодарность - person user782104; 06.02.2015
comment
многие люди делают эту ошибку, помните, что вы добавляете транзакцию в задний стек, поэтому, как правило, транзакция для добавления первого фрагмента в поток НЕ должна добавляться в задний стек (почему вы когда-либо захотите вернуться в пустое состояние? ) - person hmac; 22.01.2021

Поскольку «задний стек» имеет поведение, подобное стеку... последний вошел, первый ушел... последний фрагмент, который вы добавили в задний стек, будет выталкиваться из заднего стека первым. Вам нужно будет реализовать требуемое поведение вручную, указав свое собственное. Это не так сложно, используя методы класса FragmentManager.

Если вы «пометите» свои фрагменты при добавлении их в транзакцию...

 fragmentTransaction.add(new FragmentA(), "FragmentA_Tag");

позже вы можете определить, какой фрагмент показывать при нажатии кнопки "Назад"...

FragmentA f = fragmentManager.findFragmentByTag("FragmentA_Tag");
if(f != null){
    f.show();
}

Как вы определяете, какой фрагмент показывать, зависит только от вас. Вы можете отслеживать текущий видимый фрагмент или использовать isHidden метод класса Fragment... Кстати, здесь я говорю о нативных фрагментах, а не о поддерживаемом библиотечном фрагменте.

person Leo    schedule 06.02.2015

Backstack содержит записи о транзакциях, а не сами фрагменты. Таким образом, вы не должны добавлять запись первой транзакции (null -> fragA) в стопку. И все остальные записи транзакций должны быть добавлены в стопку. В этом случае у вас preformpopBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); андроид удалил все фрагменты, кроме fragA, потому что нет никаких записей о том, как добавлялся fragA.

person inverse12    schedule 06.02.2015

Всего несколько дней назад я начал изучать фрагменты в Android. И я тоже столкнулся с этой проблемой. Здесь я показываю свое решение и то, как я это решаю. Пожалуйста, исправьте, если мой код неверен. Что мы имеем на данный момент? Активность, множество фрагментов и их бэкстек. Мы хотим открыть каждый фрагмент из меню Drawer и очистить все остальные фрагменты из backstack. Но мы должны удерживать только один фрагмент Дома. Когда мы остаемся на фрагменте Home и пользователь нажимает кнопку «Назад», приложение закрывается.

Activity.class

protected void onCreate(Bundle savedInstanceState)
{
    ...
    // adding Home fragment without adding transaction into backstack
    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.container, HomeFragment.newInstance("args"), null);
    ft.commit();
}

@Override
public void onBackPressed() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        finish();
    }
}

public void addFragmentFromMenu(Fragment fragment){
    String backStateName =  fragment.getClass().getName();
    clearBackStack();
    FragmentManager manager = getSupportFragmentManager();
    if(manager.getBackStackEntryCount()> 0)
    {
        boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);

        if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
            //fragment not in back stack, create it.
            addFragment(fragment, manager, backStateName);
        }
    }
    else // no fragments
    {
        addFragment(fragment, manager, backStateName);
    }
}

public void addFragment(Fragment fragment, FragmentManager manager, String backStateName)
{
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.container, fragment, backStateName);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(backStateName);
    ft.commit();
}

public void clearBackStack() {
    getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}

И при нажатии на пункт меню ящика

@Override
public boolean onNavigationItemSelected(MenuItem item) {

    int id = item.getItemId();

    if (id == R.id.nav_camera) {
        addFragmentFromMenu(CameraFragment.newInstance("cam1", "cam2"));
    } else if (id == R.id.nav_gallery) {
        addFragmentFromMenu(TestFragment.newInstance("test1","test2"));
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}
person Trancer    schedule 29.01.2017

Просмотрев множество постов, я понял это следующим образом:

в методе fragC => fragD выполните две транзакции:

1 очистить задние стеки, fragC => fragA

2 фрагА => фрагD

Но таким образом исходное состояние fragA может быть разрушено.

public static void changeFragCtoD(FragmentManager fm, Fragment fragD){
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    FragmentTransaction fragmentTransaction = fm.beginTransaction();
    fragmentTransaction
            .replace(R.id.containerViewId, new fragAClass())
            .commit();

    FragmentTransaction fragmentTransaction = fm.beginTransaction();
    fragmentTransaction
            .replace(R.id.containerViewId, fragD)
            .addToBackStack(fragD.getClass().getName())
            .commit();
}

Теперь нажатие на fragD возвращает к fragA.

person Fews    schedule 18.09.2019

Я сделал следующим образом. Очистить весь фрагмент, затем добавить первый домашний фрагмент

FragmentManager fm = getActivity().getSupportFragmentManager();
                    fm.popBackStack(Constants.TAG_HOME, FragmentManager.POP_BACK_STACK_INCLUSIVE);

                    ((MainActivity) activity).manageFragment(new HomeFragment(), Constants.TAG_HOME);
 //        write down below function in main activity              
     public void manageFragment(Fragment fragment, String tag) {

            FragmentManager fragmentManager = getSupportFragmentManager();
            if (!fragmentManager.popBackStackImmediate(tag, 0)) {

                FragmentTransaction ft = fragmentManager.beginTransaction();
                ft.add(R.id.content_frame, fragment, tag);
                ft.addToBackStack(tag);
                ft.commit();

            }
        }
person Rajesh Nasit    schedule 18.08.2017

1) Добавьте первый фрагмент, используя код ниже

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
        android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
        if (fm.findFragmentById(R.id.fragment_container) != null) {
            ft.hide(fm.findFragmentById(R.id.fragment_container));
        }
        ft.add(R.id.fragment_container, new OneFragment(),OneFragment.class.getCanonicalName())
                .addToBackStack(OneFragment.class.getCanonicalName()).commit();

2) Добавьте второй фрагмент из первого фрагмента, используя код ниже

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                    android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                    if (fm.findFragmentById(R.id.fragment_container) != null) {
                        ft.hide(fm.findFragmentById(R.id.fragment_container));
                    }
                    ft.add(R.id.fragment_container,new TwoFragment(),TwoFragment.class.getCanonicalName())
.addToBackStack(TwoFragment.class.getCanonicalName()).commit();

3) Добавьте третий фрагмент из второго фрагмента, используя приведенный ниже код.

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                if (fm.findFragmentById(R.id.fragment_container) != null) {
                    ft.hide(fm.findFragmentById(R.id.fragment_container));
                }
                ft.add(R.id.fragment_container, new ThreeFragment(),ThreeFragment.class.getCanonicalName())
                        .addToBackStack(ThreeFragment.class.getCanonicalName()).commit();

4) Добавьте четвертый фрагмент из третьего фрагмента, используя приведенный ниже код.

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                if (fm.findFragmentById(R.id.fragment_container) != null) {
                    ft.hide(fm.findFragmentById(R.id.fragment_container));
                }
                ft.add(R.id.fragment_container, new FourFragment(),ThreeFragment.class.getCanonicalName())
                        .addToBackStack(FourFragment.class.getCanonicalName()).commit();

5) onBackPressed() пожалуйста, напишите ниже код

@Override
    public void onBackPressed() {
        hideKeyboard(MainActivity.this);
        Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);

        if (currentFragment.getClass().getName().equalsIgnoreCase(FourFragment.class.getName())) { // Using this code come from third fragment to first fragment
            Fragment f = this.getSupportFragmentManager().findFragmentByTag(TwoFragment.class.getCanonicalName());
            if (f != null) {
                this.getSupportFragmentManager().popBackStackImmediate(f.getClass().getCanonicalName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
        }else {
            super.onBackPressed();
        }
    }
person Community    schedule 24.08.2018

Запомните мои слова, полные FragmentTransaction добавляются в backstack, а не только фрагмент, это означает, что даже если вы добавите и удалите фрагмент в одной транзакции, вызов poBackStack() отменит всю транзакцию. Передача тега в его аргументе извлекает всю транзакцию до помеченной транзакции или даже извлекает помеченную транзакцию (в случае, если FragmentManager.POP_BACK_STACK_INCLUSIVE добавлено к аргументу). Так что это больше о том, как вы добавили ее, а не о том, как вы ее удалили. См. раздел Выполнение транзакций фрагментов.

person guneetgstar    schedule 03.10.2019

Я знаю, что уже слишком поздно отвечать на ваш вопрос, но это может быть полезно другим людям. Поскольку я искал решение в течение последних нескольких дней... Я решил его с помощью цикла for, и я думаю, что это самый простой способ.

Сначала инициализируйте целое число таким образом

int count = getSupportFragmentManager().getBackStackEntryCount();

где getBackStackEntryCount() будет подсчитывать количество транзакций.

И затем непосредственно перед вызовом метода FragmentTransaction в вашем fragD добавьте это для цикла

for (int i = 0; i < count; i++){
                getSupportFragmentManager().popBackStack();
            }

цикл for поможет вам, а popBackStack() вернет вас к фрагменту A.

это выглядит так

int count = getSupportFragmentManager().getBackStackEntryCount();
            for (int i = 0; i < count; i++){
                getSupportFragmentManager().popBackStack();
            }
            fragmentTransaction.replace(R.id.frame_layout, new FoodFragment(), "Food").addToBackStack(null);
            fragmentTransaction.commit();
person Marko Malbasic    schedule 22.04.2020

Вы переопределяете onbackpressed (Mainactivity) и, используя getBackStackEntryCount() диспетчера фрагментов, вы можете проверить, не равно ли оно 1, и popbackstack только для этого условия.

@Override
public void onBackPressed() {
  if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
     if (!(getSupportFragmentManager().getBackStackEntryCount() == 1)) {
      getSupportFragmentManager().popBackStack() ;
    }
  }    
}

person Neb King    schedule 22.08.2020