Очистіть задній стек за допомогою фрагментів


244

Я переніс свій додаток для Android на соти і зробив великий рефактор для того, щоб використовувати фрагменти. У попередній версії, коли я натискав кнопку «Домашня», я робив «a» 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
Що ж, це рівноцінно натисканню кнопки "Назад" один чи більше разів, тому вона змінює фрагмент, який зараз видно. (Принаймні, коли я це спробував)
Peter Ajtai

7
У мене те саме питання, що і у Пітера. Я хотів би очистити всі фрагменти, а не переробляти їх, що має багато наслідків. Наприклад, ви потрапите на події життєвого циклу, які вам не потрібні, послідовно вискакуючи кожен фрагмент зі стека.
Брайан Гріффі

233
Для переходу до вершини просто використовуйте: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit

53
Для чого це варто, використовуючи fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); працював для мене ще краще, бо заважав виконувати анімаційні фрагменти
roarster

17
Це НЕ працює належним чином - це призведе до виклику для початку кожного фрагмента посеред
Джеймс

165

Щоб відповісти на коментар @ Warpzit і полегшити пошук інших.

Використання:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Я вважаю, що таким чином вискочив усі фрагменти із задніх рук, було порушено в останній бібліотеці 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);

Де назва - параметр addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

навіть якщо ви заміните стек .fragment буде живим, але не видно
Asthme

8

Я просто хотів додати: -

Вискакуючи з рюкзака, використовуючи наступні

fragmentManager.popBackStack ()

йдеться лише про видалення фрагментів з транзакції, ніяким чином він не збирається видаляти фрагмент з екрану. Тож в ідеалі це може бути вам не видно, але можуть бути два-три фрагменти, складені один над одним, а при натисканні клавіші на звороті користувальницький інтерфейс може виглядати захаращеним, укладеним.

Просто взявши простий приклад: -

Припустимо, у вас є фрагмент A, який завантажує Fragmnet B, використовуючи fragmentmanager.replace (), і тоді ми робимо addToBackStack, щоб зберегти цю транзакцію. Отже, потік:

КРОК 1 -> FragmentA-> FragmentB (ми перейшли до FragmentB, але фрагмент A знаходиться у фоновому режимі, не видно).

Тепер ви виконуєте деяку роботу з фрагментом B і натискаєте кнопку «Зберегти», яка після збереження повинна повернутися до фрагменту A.

КРОК 2-> Після збереження FragmentB ми повертаємося до FragmentA.

КРОК 3 -> Отже, поширеною помилкою буде ... у фрагменті B ми зробимо фрагмент Manager.replace () фрагментB з фрагментомA.

Але що насправді відбувається, ми знову завантажуємо фрагмент A, замінюючи FragmentB. Отже, зараз є два FragmentA (один із STEP-1, а один із цього STEP-3).

Два екземпляри FragmentsA розміщені один над одним, що може бути не видно, але воно є.

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

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


3

Читаючи документацію та вивчаючи, що таке ідентифікатор фрагмента, він здається просто індексом стека, тому це працює:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero ( 0) - це нижня частина стека, тому спливаюче підключення до неї очищає стек.

CAVEAT: Хоча вищезазначене працює в моїй програмі, я трохи вагаюся, тому що документація FragmentManager ніколи фактично не говорить про те, що id - це індекс стека. Має сенс, що це було б, і всі мої журнали налагодження викривляють, що це є, але, можливо, за якихось особливих обставин це не буде? Чи може хтось підтвердити це так чи інакше? Якщо це так, то вищезгадане - найкраще рішення. Якщо ні, це альтернатива:

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

1
Як щодо використання fragmentManager..getBackStackEntryAt(0).getId()замість 0? Це повинно працювати навіть у тому випадку, якщо ідентифікатори запису за спинками в якийсь момент відрізняються від індексу стека.
ChristophK

3

Просто скористайтеся цим методом і передайте тег контексту та фрагмента, до якого нам потрібно видалити фрагменти backstake.

Використання

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.