Це правильний спосіб очищення заднього стека фрагментів, залишаючи глибоко вкладений стек?


130

Я використовую бібліотеку сумісності Android для реалізації фрагментів і розширив зразок макета, щоб фрагмент містив кнопку, яка звільняє інший фрагмент.

На панелі вибору зліва у мене є 5 елементів, що вибираються - A B C D E.

Кожен завантажує фрагмент (через FragmentTransaction:replace) на панель деталей -a b c d e

Тепер я розширив фрагмент, eщоб містити кнопку, яка завантажує ще один фрагмент e1також у області деталей. Я зробив це за eметодом onClick фрагмента наступним чином:

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

Якщо я роблю такі вибір:

E - e - e1 - D - E

Потім фрагмент eзнаходиться в області деталей. Це добре і те, що я хочу. Однак якщо я натиснув backкнопку в цей момент, вона нічого не робить. Я мушу двічі клацнути по ньому, тому що e1все ще є на стеці. Крім того, натиснувши навколо, я отримав нульове виключення вказівника у onCreateView:

Щоб "вирішити" цю проблему, я додав наступне щоразу, коли A B C D Eвибрано:

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

Просто цікаво, чи це правильне рішення чи я повинен робити щось інше?

Відповіді:


252

Ну, є кілька способів зробити це в залежності від наміченої поведінки, але це посилання має дати вам найкращі рішення, і не дивно, що це від Діанні Хакборн

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

По суті у вас є такі варіанти

  • Використовуйте назву для початкового стану зворотного стека та використовуйте FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Використовуйте FragmentManager.getBackStackEntryCount()/, getBackStackEntryAt().getId() щоб отримати ідентифікатор першого запису на зворотному стеку, і FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) повинен вискакувати всю задню частину ... Я думаю, що документація для цього просто неправильна. (Насправді, я думаю, це просто не охоплює випадок, коли ви переходите POP_BACK_STACK_INCLUSIVE),

Що це означає? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). GetId ()
dannyroa

4
2-й працював на мене. Що це означає для очищення всього стека: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL

@JorgeGarcia чи можливо після popbackstack ми просто закінчимо наш фрагмент без перезавантаження старішого.
diggu

Зверніть увагу, існує також версія popBackStackImmediate (), оскільки popBackStack () є асинхронною, тобто очищення не відбувається в той самий момент, коли ви викликаєте метод.
Генк

6
Заявляє, що групу заборонено як спам, і я не можу отримати доступ до посилання :( хтось має ресурс в іншому місці?
EpicPandaForce

61

Інше чисте рішення, якщо ви не хочете розміщувати всі записи стека ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

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


1
Це дуже погано: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);перед тим, як замінити () , так як завантажуються покликання Fragment onCreateView(), onActivityCreated()і т.д. Відновлення і Destroing фрагмент миттєво погано. Фрагмент може зареєструвати, наприклад, приймач. Це впливає на продуктивність.
ВасилеМ

@VasileM, ви могли б детально описати? У яких випадках це погано? Це через асинхронну поведінку FragmentTransaction? Чи є лише погана продуктивність неправильного стека фрагмента?
CoolMind

27

Завдяки відповіді Йоахіма , я використовую код, щоб остаточно очистити всі записи в задній стек.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
Для чого тут використовувати цикл? Для мене FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) очистив усі записи в задній стек ...
Marek

3
@Marek, оскільки іноді не всі фрагменти потрібно видалити, для цього підходить цикл.
CoolMind

1
@CoolMind, це все ще не має для мене сенсу. popBackStack(backStackId, INCLUSIVE)поверне всі фрагменти (стани) назад до backStackId, тож як тільки ви випустите найнижчий рівень, iякий ви збираєтеся вискочити, всі вищі повинні одночасно вискочити. То в чому сенс циклу?
LarsH

@LarsH, ти маєш рацію. Дивіться stackoverflow.com/a/59158254/2914140 . Для того, щоб передати інші фрагменти до потрібного тегу, спершу слід додати фрагмент з addToBackStack ( тег ).
CoolMind

7

Я багато досліджував з очищення Backstack, і нарешті побачив Transaction BackStack та його управління . Ось рішення, яке найкраще працювало для мене.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

Вищеописаний метод перебирає всі транзакції в backstack і видаляє їх відразу по черзі.

Примітка: вищевказаний код колись не працює, і я стикаюся з ANR через цей код, тому, будь ласка, не намагайтеся цього.

Оновлення нижче методом видалити всі фрагменти цього "імені" з backstack.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • ім'я Якщо недійсне, це ім'я попереднього зворотного стану, який потрібно шукати; якщо його знайдуть, всі держави до цього стану будуть спливати. The
  • Прапор POP_BACK_STACK_INCLUSIVE може бути використаний для контролю того, чи з’являється сам названий стан. Якщо нуль, спливає лише верхній стан.

Я не бачу, чому ви видаляєте їх по черзі. Чи є причина, чому ви обрали для цього рішення замість інших рішень? Чи є причина видаляти їх по одному замість усіх відразу?
miva2

Немає способу одночасно видалити backstack, дивіться developer.android.com/reference/android/app/…
Lokesh

3

Я використовую аналогічний код, як і той, що використовує цикл while, але я називаю кількість записів у кожному циклі ... тому я припускаю, що це дещо повільніше

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

Як написано у розділі Як вискочити фрагмент із задніх куточків та тут LarsH , ми можемо виконувати декілька фрагментів зверху вниз до специфічного тегу ( разом із тегом ), використовуючи цей метод:

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

Замініть "фрагмент" тегом вашого фрагмента. Пам’ятайте, що спочатку ми повинні додати фрагмент до backstack за допомогою:

fragmentTransaction.addToBackStack("frag")

Якщо ми додамо фрагменти за допомогою addToBackStack(null), ми не відобразимо фрагменти таким чином.


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.