Очистить задний стек, используя фрагменты

244

Я портировал свое Android-приложение на сотовые и сделал большой рефакторинг, чтобы использовать фрагменты. В моей предыдущей версии, когда я нажимал кнопку «Домой», я делалACTIVITY_CLEAR_TOP для сброса заднего стека.

Теперь мое приложение представляет собой одно действие с несколькими фрагментами, поэтому, когда я нажимаю кнопку «Домой», я просто заменяю один из фрагментов внутри него. Как я могу очистить свой стек обратно без необходимости использовать startActivityс ACTIVITY_CLEAR_TOPфлагом?

biquillo
источник
Избегайте использования задних стеков! это не очень помогает с общей эффективностью! используйте обычную замену () или, что еще лучше, удаляйте / добавляйте каждый раз, когда хотите перейти! Посмотрите мой пост на stackoverflow.com/questions/5802141/…
stack_ved

Ответы:

430

Я выложил нечто подобное здесь

Из ответа Иоахима от Дайан Хакборн:

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

В итоге я просто использовал:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

Но в равной степени мог бы использовать что-то вроде:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

Который выскочит все состояния до названного. Затем вы можете просто заменить фрагмент на то, что вы хотите

PJL
источник
8
Что ж, это эквивалентно нажатию кнопки «Назад» один или несколько раз, поэтому он изменяет фрагмент, который виден в данный момент. (По крайней мере, когда я попробовал это)
Питер Айтай
7
У меня та же проблема, что и у Питера. Я хотел бы очистить все фрагменты, а не циклически проходить по ним, что имеет много последствий. Например, вы попадете на события жизненного цикла, которые вам не нужны, последовательно выталкивая каждый фрагмент из стека.
Брайан Гриффи
233
Чтобы перейти наверх, просто используйте: fragManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit
53
Для чего это стоит, используя FragManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); работал еще лучше для меня, поскольку это препятствовало выполнению анимации фрагмента
roarster
17
Это НЕ работает должным образом - это вызовет onStart для каждого фрагмента между ними
Джеймс
165

Чтобы ответить на комментарий @ Warpzit и облегчить поиск для других.

Использование:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Мортен Холмгаард
источник
14
Я считаю, что выталкивание всех фрагментов из backstack таким образом было нарушено в последней библиотеке v7-appCompat при использовании AppCompatActivity. После обновления моего приложения до самой последней библиотеки v7-appCompat (21.0.0) и расширения новой AppCompatActivity добавление фрагментов указанным выше способом оставляет некоторые фрагменты в записи обратного стека FragmentManager. Я бы посоветовал не использовать это.
dell116
Может быть использовать popBackStackImmediate.
Kannan_SJD
38

При всем уважении ко всем вовлеченным сторонам; Я очень удивлен, увидев, сколько из вас может очистить весь стек обратно с помощью простого

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Согласно документации Android (в отношении nameаргумента - «ноль» в заявленных рабочих предложениях).

Если ноль, только верхнее состояние выталкивается

Теперь я понимаю, что мне не хватает знаний о ваших конкретных реализациях (например, сколько записей у вас в заднем стеке на данный момент времени), но я бы поставил все свои деньги на принятый ответ, ожидая четко определенного Поведение более широкого круга устройств и поставщиков:

(для справки, что-то вместе с этим)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}
дБмВт
источник
4
для меня это не было , так как каждый поп принимает вас внутри к onCreateView каждого фрагмента. Где бы я получил NPE на каком-то ресурсе. Но с использованием fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); просто убил весь бэкстэк.
sud007
1
Любые идеи о том, как пропустить вызовы onCreateView при появлении с помощью цикла?
Аюш Гоял
Очистка самого верхнего фрагмента (null) удалит все фрагменты, которые идут после него в заднем стеке.
2b77bee6-5445-4c77-b1eb-4df3e5
18

У меня работает и простой способ без использования цикла:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Мд Мохсин
источник
17

Принятого ответа мне не хватило. Я должен был использовать:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}
Belphegor
источник
2
На это было указано в другом ответе, но только для того, чтобы убедиться, что он отмечен: если вы сложите весь стек в цикле, как это, вы будете запускать методы жизненного цикла для каждого фрагмента между началом и концом стека. , Существует большая вероятность, что в большинстве случаев такая реализация будет иметь непредвиденные последствия. Стоит также отметить, что popBackStackImmediate()транзакция выполняется синхронно, что, как правило, не рекомендуется.
Дэмиен Дил
16

Очистить бэкстек без петель

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Где name это параметр addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)
georgehardcore
источник
даже если вы замените стек .fragment, он будет жив, но не виден
Asthme
8

Я просто хотел добавить:

Выскочить из backstack, используя следующие

fragmentManager.popBackStack ()

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

Просто приведу простой пример:

Предположим, у вас есть фрагмент A, который загружает Fragmnet B с использованием fragmanager.replace (), а затем мы добавляем addToBackStack, чтобы сохранить эту транзакцию. Итак, поток:

ШАГ 1 -> FragmentA-> FragmentB (мы переместились в FragmentB, но Fragment A находится в фоновом режиме, не виден).

Теперь вы выполняете некоторую работу во фрагменте B и нажимаете кнопку «Сохранить», которая после сохранения должна вернуться к фрагменту A.

ШАГ 2-> При сохранении FragmentB мы возвращаемся к FragmentA.

ШАГ 3 -> Так что распространенная ошибка будет ... во фрагменте B мы сделаем фрагмент Manager.replace () фрагментB с фрагментом A.

Но что на самом деле происходит, мы снова загружаем фрагмент А, заменяя фрагмент Б. Итак, теперь есть два фрагмента A (один из STEP-1 и один из этого STEP-3).

Два экземпляра фрагментов A накладываются друг на друга, которые могут быть не видны, но они есть.

Таким образом, даже если мы очищаем backstack вышеупомянутыми методами, транзакция очищается, но не фактические фрагменты. Так что в идеале в таком конкретном случае при нажатии кнопки сохранения вам просто нужно вернуться к фрагменту A, просто выполнив fm.popBackStack () или fm.popBackImmediate () .

Так что правильно Step3-> fm.popBackStack () вернуться к фрагменту A, который уже находится в памяти.

Никс
источник
3

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

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Ноль ( 0) - это нижняя часть стека, поэтому всплывающее окно до него включительно очищает стек.

ПРЕДУПРЕЖДЕНИЕ. Хотя вышесказанное работает в моей программе, я немного сомневаюсь, потому что документация FragmentManager фактически никогда не утверждает, что id является индексом стека. Это имеет смысл, и все мои журналы отладки показывают, что это так, но, может быть, в некоторых особых обстоятельствах это не так? Кто-нибудь может подтвердить это так или иначе? Если это так, то вышеупомянутое является лучшим решением. Если нет, то это альтернатива:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
транс
источник
1
Как насчет использования fragmentManager..getBackStackEntryAt(0).getId()вместо 0? Это должно работать, даже если идентификаторы записей backstack в какой-то момент отличаются от индекса стека.
ChristophK
3

Просто используйте этот метод и передайте тег Context & Fragment, в который нам нужно удалить фрагменты обратного удара.

использование

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}
Архат Бэйд
источник
2

Привет ~ Я нашел решение, которое гораздо лучше, с: https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}
Chenxi
источник
2
Пожалуйста, расширите свой ответ, почему это решение лучше.
Simon.SA
Он использует механизм, который предоставляет sdk, и не вызывает проблем с npe.
Chenxi
1

Я получил это работает так:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}
saulobrito
источник
1

Это работает для меня, попробуйте это:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }
Алок Сингх
источник
0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Вызов этого метода будет очень аккуратным.

  1. Петля не требуется.
  2. Если вы используете анимацию во фрагментах, она не будет отображать слишком много анимаций. Но использование цикла будет.
Ваджид Али
источник
0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}
user3509903
источник
Спасибо за этот фрагмент кода, который может предоставить некоторую ограниченную, немедленную помощь. Надлежащее объяснение будет значительно улучшить свою долгосрочную ценность, показывая , почему это является хорошим решением проблемы и сделает его более полезным для читателей будущих с другими подобными вопросами. Пожалуйста, измените свой ответ, чтобы добавить некоторые объяснения, в том числе предположения, которые вы сделали.
Абделила Эль Айссауи