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

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

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

16 ответов

Решение

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

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

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

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

FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

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

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

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

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

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

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

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

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)

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

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

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

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

Привет ~ Я нашел решение, которое гораздо лучше, с: 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);
    }
}

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

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

fragmentManager.popBackStack()

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

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

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

ШАГ 1 -> FragmentA->FragmentB (мы переместились во FragmentB, но фрагмент 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, который уже находится в памяти.

Для тех, кто живет здесь, котлинов:

      repeat(supportFragmentManager.backStackEntryCount) {
    supportFragmentManager.popBackStack()
}

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

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

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

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

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

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

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

Просто используйте этот метод и передайте тег 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();
    }
}

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

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

Расширение Котлина

      fun AppCompatActivity.clearAllFragments() {
    supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

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

  1. Петля не требуется.
  2. Если вы используете анимацию во фрагментах, она не будет отображать слишком много анимаций. Но с помощью цикла будет.
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;
}
Другие вопросы по тегам