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


244

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

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


Избегайте использования задних стеков! это не очень помогает с общей эффективностью! используйте обычную замену () или, что еще лучше, удаляйте / добавляйте каждый раз, когда хотите перейти! Посмотрите мой пост на 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)

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


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

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)

даже если вы замените стек .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);
    }
}

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

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;
}

Спасибо за этот фрагмент кода, который может предоставить некоторую ограниченную, немедленную помощь. Надлежащее объяснение будет значительно улучшить свою долгосрочную ценность, показывая , почему это является хорошим решением проблемы и сделает его более полезным для читателей будущих с другими подобными вопросами. Пожалуйста, измените свой ответ, чтобы добавить некоторые объяснения, в том числе предположения, которые вы сделали.
— Абделила Эль Айссауи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.