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


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.