Як отримати фрагмент для видалення себе, тобто його еквівалента закінчення ()?


230

Я перетворюю додаток для використання фрагментів за допомогою бібліотеки сумісності. Зараз у мене є ряд видів діяльності (ABCD), які ланцюжком ставляться один до одного, у D є кнопка «ОК», яка при натисканні закінчується дзвінками, яка потім перекидається, onActivityResult()щоб додатково знищити C і B.

Для моєї попередньої версії фрагмента Honycomb кожна діяльність є ефективно обгорткою фрагментів Af Bf Cf Df. Всі заходи, розпочаті через startActivityForResult()і onActivityResult()всередині кожного з фрагментів, можна радісно зателефонуватиgetActivity().finish()

Проблема, з якою у мене є, у моїй версії Honeycomb у мене є лише одна активність, A, а фрагменти Bf, Cf, Df завантажуються за допомогою FragmentManager.

Що я не розумію - це робити в Df, коли натискається "OK", щоб видалити фрагменти Df, Cf і Bf?

Я спробував, щоб фрагмент вискакував із стека, але це призвело до виключення. onActivityResult()марно, тому що я не завантажив фрагмент за допомогою startActivityForResult().

Чи я думаю про це зовсім неправильно? Чи повинен я реалізувати якогось слухача, який спілкується з батьківським фрагментом або діяльністю, щоб зробити поп, використовуючи менеджер транзакцій?


7
як щодо ((YourActivity) getActivity ()). onBackPress ();
Viswanath Lekshmanan

@ViswanathLekshmanan ваша відповідь на коментар корисна для мене .. 1 Оновлення від мене
Abhishek Singh

@AbhishekSingh Приємно чути :)
Viswanath Lekshmanan

@ViswanathLekshmanan :)
Абхішек Сінгх

Відповіді:


62

Що я не розумію - це робити в Df, коли натискається "OK", щоб видалити фрагменти Df, Cf і Bf?

Крок №1: Попросіть Df сказати D "yo! за допомогою виклику методу або на самій активності, або на екземплярі інтерфейсу, що надається активністю.

Крок №2: Дозвольте D видалити фрагменти за допомогою FragmentManager.

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


Але в моїй версії Honeycomb немає D, це моє важко. Існує просто активність A, яка завантажує фрагмент Bf, який завантажує Cf, який завантажує Df, використовуючи FragmentTransaction.
PJL

1
@PJL: Вибачте, я мав на увазі А. Це одна з причин використовувати інтерфейс для слухачів, тому багато дій можуть реагувати на події "ми отримали ОК натисніть" від Df.
CommonsWare

1
Поки я зараз переношу повідомлення, я викликав метод слухача з фрагментів методу onActivityResult Df у діяльність, після чого я потім викликав popBackStack на FragmentManager. Однак це призводить до витягу "IllegalStateException: Не можу виконати цю дію після onSaveInstanceState". Будь-які ідеї, як я можу це подолати?
PJL

1
@DiegoPalomar: finish()повинно вистачити.
CommonsWare

1
@ user3364963: Минув час, коли я досліджував це, але IIRC, він руйнується, коли він вискакує з заднього стека. Додайте onDestroy()метод до свого фрагмента і подивіться, чи його викликають.
CommonsWare

313

Хоча це може бути не найкращим підходом до найближчого еквівалента, я можу подумати, що це працює саме з бібліотекою підтримки / сумісності

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

або

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

інакше.

Крім того, ви можете використовувати рюкзак і попс. Однак майте на увазі, що фрагмент може не знаходитися на задньому куті (залежно від фрагмента трансакції, який він там отримав ..), або він може бути не останнім, хто потрапив на стек, тому спливаючий стек може видалити неправильний ...


11
Хоча цей підхід працює, якщо ви використовуєте addToBackStack (null), він залишить обробник кнопки "назад" +1. Тож доведеться натиснути її двічі.
користувач123321

34
"поп" фрагмент з FragmentManager.
користувач123321

2
Я спробував вищевказану процедуру, але вона видає цю помилку "java-lang -legalstateexception-can-not-perform-this-action-after-onsavein substance". Тож де саме я маю вилучити фрагмент
KK_07k11A0585

6
Ця відповідь є поганою практикою і не повинна набирати голосів. Фрагменти не призначені для усвідомлення себе подібними. Це вбиває багаторазове використання, в чому суть фрагментів! Фрагмент повинен сигналізувати про активність для його видалення за допомогою будь-якої кількості засобів. Метод інтерфейсу зворотного дзвінка - популярний вибір. developer.android.com/training/basics/fragments/…
коланти

2
@ManfredMoser Я не згоден. Це дуже суть питання. У нього є ціла послідовність фрагментів для видалення. У цьому коді немає нульових перевірок чи перевірок на додавання дії. Він вирветься у виробництві, оскільки це залежить від занадто багато речей, яких фрагмент не знає.
знімки на колонці

263

Ви можете використовувати підхід нижче, він прекрасно працює:

getActivity().getSupportFragmentManager().popBackStack();

44
Ця відповідь ніби в 10 разів краща за прийняту - прямо до суті.
nikib3ro

50
Це також в 10 разів гірше щодо дизайну, ніж прийнятий. Фрагмент повинен бути маленьким "помічником" у діяльності і ніколи не повинен контролювати себе чи інші фрагменти
Патрік

6
Рішення невірне, як вказував @avalancha. Подивіться на developer.android.com/guide/components/…
the_dark_destructor

2
Я використовую цей метод onActivityResult і отримую помилку "Неможливо виконати цю дію після onSaveInstanceState". Як я можу це вирішити?
Jayeshkumar Sojitra

1
popBackStack()- це єдине рішення, яке працює, коли ви хочете повернути заголовок рядка дій до попереднього стану після видалення фрагмента. Інакше мені не потрібно буде поєднувати обидва рішення з високою оцінкою із stackoverflow.com/questions/13472258/…, і це рішення тут завжди встановлювати належну назву рядка дій після різних випадків використання. наприклад, натискання назад, видалення, додавання заміни тощо.
Бевор

36

Ви повинні дозволити Діяльності займатися додаванням та видаленням фрагментів, як каже CommonsWare, використовувати слухач. Ось приклад:

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}

5
Самогубство багато емо стилю? Як щодо "SelfClosing" або "AutoClose" або "SmartClose" (r)
DritanX

21
це не закриває це ВМЕРИТИ ВИНАГИ ;-(
Blundell

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

7
Технічно, якщо нам належить активність вбити фрагмент, то фрагмент не є самогубним. Активність є самогубною.
Кейсі Мюррей

17

У розділі Діяльність / AppCompatActivity:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

а потім зателефонуйте у фрагмент:

getActivity().onBackPressed();

або як зазначено в інших відповідях, називайте це у фрагменті:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

5

Якщо ви використовуєте новий навігаційний компонент, просто

findNavController().popBackStack()

Це зробить всі FragmentTransaction позаду для вас.


4

Перевірте, чи задовольняються ваші потреби діалоговим фрагментом. DialogFragment має метод dismiss (). Набагато чистіший на мій погляд.


3

Я створюю простий метод для цього

popBackStack(getSupportFragmentManager());

Чим розмістити його в моєму класі ActivityUtils

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Це чудово працює, отримуйте задоволення!


2
Я не розумію мету вашого методу. Оригінальний popBackStack видається цілком адекватним.
Неймовірний

1

OnCreate:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

Ось так я приховую фрагмент у події 1 клацання

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

Потім показує його назад int подія 2

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();

1

Якщо вам потрібно відскочити від четвертого фрагмента в історії загин до першого, використовуйте теги !!!

Додаючи перший фрагмент, ви повинні використовувати щось подібне:

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

або

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

І коли ви хочете показати фрагменти B, C і D, ви використовуєте це:

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

та інші листи ...

Щоб повернутися до FragmentA, просто зателефонуйте popBackStack(0, "A"), так, використовуйте прапор, який ви вказали під час додавання, і зауважте, що це повинен бути той самий прапор у команді addToBackStack(), а не той, який використовується у команді замінити чи додати.

Ласкаво просимо ;)


Я перевірив 'popBackStack (0, "A") ", і моя програма повертається до фрагмента A, але я хочу, щоб цей фрагмент був видалений із Back Stack ... Як я можу видалити фрагмент із Stack, не відображаючись на екрані ??
KryNaC


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.