Різниця між add (), substitute () та addToBackStack ()


300

У чому полягає основна відмінність між викликом цих методів:

fragmentTransaction.addToBackStack(name);
fragmentTransaction.replace(containerViewId, fragment, tag);
fragmentTransaction.add(containerViewId, fragment, tag);

Що означає замінити вже наявний фрагмент та додати фрагмент до стану активності та додати активність до задньої стеки?

По-друге, з findFragmentByTag(), чи шукає цей тег доданий add()/ replace()методом чи addToBackStack()методом?

Відповіді:


331

1) fragmentTransaction.addToBackStack(str);

Опис - додайте цю транзакцію до зворотного стеку. Це означає, що транзакція запам’ятається після її вчинення, і вона поверне свою дію, коли пізніше вискочить стек.

2) fragmentTransaction.replace(int containerViewId, Fragment fragment, String tag)

Опис - замініть наявний фрагмент, який було додано до контейнера. Це по суті те саме, що викликати видалити (Fragment) для всіх доданих в даний час фрагментів, які були додані з одним і тим же контейнеромViewId, а потім додати (int, Fragment, String) з тими ж аргументами, наведеними тут.

3) fragmentTransaction.add(int containerViewId, Fragment fragment, String tag)

Опис - додайте фрагмент до стану активності. Цей фрагмент необов'язково може також мати свій вид (якщо Fragment.onCreateView повертає ненулеве значення) у перегляд контейнера діяльності.

Що означає замінити вже наявний фрагмент та додати фрагмент до стану активності та додати активність до задньої стеки?

Існує стек, в якому зберігаються всі дії в запущеному стані. Фрагменти належать до діяльності. Таким чином, ви можете додати їх, щоб вбудувати їх у діяльність.

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

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

Ви також можете повернутися до попереднього фрагмента в backStack popBackStack()методом. Для цього вам потрібно додати цей фрагмент у стек, використовуючи addToBackStack()та потім commit()відобразити. Це в зворотному порядку із струмом зверху.

findFragmentByTag шукає тег, доданий методом додавання / заміни чи методом addToBackStack?

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

Посилання: FragmentTransaction


2
Отже, чи можу я додати фрагмент методом заміни на початку діяльності?
Йохан AI

(Жодного фрагменту раніше не додано)
Йохан AI,

2
Чи може контейнер з фрагментами містить більше одного фрагмента, якщо так, то як поводитиметься метод заміни (). Якщо він замінить усі фрагменти в цьому контейнері або андроїд-api, має метод, який приймає три аргументи, тобто frgamentContainer, новий фрагмент і яким його потрібно замінити.
ve

1
@ved Ні, він замінить усі існуючі в контейнері фрагменти на поточний.
reubenjohn

329

Ще одна важлива відмінність між собою addі replaceце:

replaceвидаляє наявний фрагмент і додає новий фрагмент. Це означає, що при натисканні кнопки "назад" фрагмент, який замінили, буде створений із onCreateViewвикликом. Тоді як addзберігається існуючий фрагмент і додається новий фрагмент, що означає, що існуючий фрагмент буде активним, і вони не будуть знаходитись у стані "призупинення", отже, коли натиснута кнопка "назад" onCreateViewне викликається для існуючого фрагмента (фрагмент, який був там, перш ніж новий фрагмент був додано).

З точки зору подій життєвого циклу фрагмента onPause, onResume, onCreateViewта інші події життєвого циклу буде викликатися в разі , replaceале вони не будуть викликатися в разі add.

Редагувати : Ви повинні бути обережними, якщо вона використовує якусь бібліотеку шини подій, як-от Eventbus Greenrobot, і повторно використовує той самий фрагмент для складання фрагмента поверх інших add. В цьому випадку, навіть якщо ви будете слідувати передовій практиці і зареєструвати автобус подій в onResumeі незареєстрованому в onPause, автобус події буде по- , як і раніше активний в кожному випадку доданого фрагмента в якості addфрагмента звичаю виклику або з цих методів фрагмента життєвого циклу. В результаті слухач шини подій у кожному активному екземплярі фрагмента оброблятиме ту саму подію, яка може бути не такою, яку ви хочете.


1
Я думаю, що одним із підходів може бути обробка події в самому верхньому фрагменті та виклик cancelEventDelivery () після завершення обробки. Більше про методи cancelEventDelivery () ви можете знайти тут github.com/greenrobot/EventBus/blob/master/…
Jeevan

6
+1 від мене. Дуже важливо знати, що заміна поточного фрагмента новим фрагментом означає, що попередній фрагмент буде відтворений, щоб повернути його під час відтворення назад із стека фрагмента.
AndaluZ

onPause, onResume тісно пов'язаний з Активністю хоста. І вони не дзвонили під час заміни фрагмента.
Зар Е Ахмер

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

Ви повинні зазначити, що ви викликаєте addToBackStack () разом із методами add () або substitution ().
rahil008

99

Приклад дії має 2 фрагменти, і ми використовуємо FragmentManagerдля заміни / додавання addToBackstackкожного фрагмента до макета в діяльності

Використовуйте заміну

Перейти фрагмент1

Fragment1: onAttach
Fragment1: onCreate
Fragment1: onCreateView
Fragment1: onActivityCreated
Fragment1: onStart
Fragment1: onResume

Перейти фрагмент2

Fragment2: onAttach
Fragment2: onCreate
Fragment1: onPause
Fragment1: onStop
Fragment1: onDestroyView
Fragment2: onCreateView
Fragment2: onActivityCreated
Fragment2: onStart
Fragment2: onResume

Поп-фрагмент2

Fragment2: onPause
Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy
Fragment2: onDetach
Fragment1: onCreateView
Fragment1: onStart
Fragment1: onResume

Попський фрагмент1

Fragment1: onPause
Fragment1: onStop
Fragment1: onDestroyView
Fragment1: onDestroy
Fragment1: onDetach

Використовуйте додавання

Перейти фрагмент1

Fragment1: onAttach
Fragment1: onCreate
Fragment1: onCreateView
Fragment1: onActivityCreated
Fragment1: onStart
Fragment1: onResume

Перейти фрагмент2

Fragment2: onAttach
Fragment2: onCreate
Fragment2: onCreateView
Fragment2: onActivityCreated
Fragment2: onStart
Fragment2: onResume

Поп-фрагмент2

Fragment2: onPause
Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy
Fragment2: onDetach

Попський фрагмент1

Fragment1: onPause
Fragment1: onStop
Fragment1: onDestroyView
Fragment1: onDestroy
Fragment1: onDetach

Зразок проекту


1
не onPause()повинен був називатися раніше onStop()на кожній поп- акції?
iCantC

відмінна відповідь для розмежування між "add ()" та "substitute ()", хоча цього немає у addToBackStack (). Upvote
Shirish Herwade

@ShirishHerwade Я вважаю, що він демонстрував різницю між додаванням та заміною на addToBackStack в обох випадках.
CyberShark

38

Хоча це старе питання, на яке вже відповіли, можливо, наступні приклади можуть доповнити прийняту відповідь, і вони можуть бути корисними для деяких нових програмістів в Android, як і я.

Варіант 1 - "addToBackStack ()" ніколи не використовується

Випадок 1A - додавання, видалення та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
add Fragment C :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
remove Fragment C :     onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Fragment B is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               App is closed, nothing is visible

Випадок 1B - додавання, заміна та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
(replace Fragment C)    
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()
Fragment C :        onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()
Fragment C :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               App is closed, nothing is visible

Варіант 2 - "addToBackStack ()" завжди використовується

Випадок 2A - додавання, видалення та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
add Fragment C :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
remove Fragment C :     onPause() - onStop() - onDestroyView()                              Fragment B is visible
(Back button clicked)
Fragment C :        onCreateView() - onActivityCreated() - onStart() - onResume()                   Fragment C is visible
(Back button clicked)
Fragment C :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Fragment B is visible
(Back button clicked)
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Fragment A is visible
(Back button clicked)
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Activity is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()                              App is closed, nothing is visible

Справа 2В - додавання, заміна, видалення та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
(replace Fragment C)    
Fragment B :        onPause() - onStop() - onDestroyView()  
Fragment A :        onPause() - onStop() - onDestroyView() 
Fragment C :        onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
remove Fragment C :     onPause() - onStop() - onDestroyView()                              Activity is visible
(Back button clicked)
Fragment C :        onCreateView() - onActivityCreated() - onStart() - onResume()                   Fragment C is visible
(Back button clicked)
Fragment C :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               
Fragment A :        onCreateView() - onActivityCreated() - onStart() - onResume()   
Fragment B :        onCreateView() - onActivityCreated() - onStart() - onResume()                   Fragment B is visible
(Back button clicked)
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Fragment A is visible
(Back button clicked)
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Activity is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()                              App is closed, nothing is visible

Варіант 3 - "addToBackStack ()" використовується не завжди (у наведених нижче прикладах, без вказується, що він не використовується)

Справа 3А - додавання, видалення та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B w/o:     onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
add Fragment C w/o:     onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
remove Fragment C :     onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Fragment B is visible
(Back button clicked)
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Activity is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()                              App is closed, nothing is visible

Справа 3B - додавання, заміна, видалення та натискання кнопки Назад

Activity :      onCreate() - onStart() - onResume()                             Activity is visible
add Fragment A :    onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment A is visible
add Fragment B w/o:     onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment B is visible
(replace Fragment C)    
Fragment B :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()   
Fragment A :        onPause() - onStop() - onDestroyView() 
Fragment C :        onAttach() - onCreate() - onCreateView() - onActivityCreated() - onStart() - onResume()     Fragment C is visible
remove Fragment C :     onPause() - onStop() - onDestroyView()                              Activity is visible
(Back button clicked)
Fragment C :        onCreateView() - onActivityCreated() - onStart() - onResume()                   Fragment C is visible
(Back button clicked)
Fragment C :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               
Fragment A :        onCreateView() - onActivityCreated() - onStart() - onResume()                   Fragment A is visible
(Back button clicked)
Fragment A :        onPause() - onStop() - onDestroyView() - onDestroy() - onDetach()               Activity is visible
(Back button clicked)
Activity :      onPause() - onStop() - onDestroy()                              App is closed, nothing is visible

1
Досить ретельно. Гарна спроба!
pulp_fiction

Тож чи можна сказати, що під час роботи з фрагментами кнопка повернення працює аналогічно функції FragmentManager.popBackStack ()?
Тінтін

чудова відповідь, не можу бути кращим. На це слід прийняти відповідь.
Shirish Herwade

25

Основна різниця між add()і replace()може бути описана як:

  • add() використовується для простого додавання фрагмента до якогось кореневого елемента.
  • replace() поводиться аналогічно, але спочатку він видаляє попередні фрагменти, а потім додає наступний фрагмент.

Ми можемо бачити точну різницю, коли використовуємо addToBackStack()разом з add()або replace().

Коли ми натискаємо кнопку назад після у випадку add()... onCreateView ніколи не викликається, але у випадку replace(), коли ми натискаємо кнопку назад ... oncreateView викликається кожен раз.


1
Тож додавання () призводить до більшого навантаження з точки зору андроїд-пам'яті, оскільки погляд попереднього фрагмента не зруйнований?
Дерекий

@Derekyy Так, я так думаю.
Арпіт Дж.

це те, що я шукав
parvez rafi

2

Коли ми додаємо перший фрагмент -> другий фрагмент, використовуючи метод add ()

 btn_one.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(),"Click First 
Fragment",Toast.LENGTH_LONG).show();

                Fragment fragment = new SecondFragment();
                getActivity().getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_frame, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();
//                        .replace(R.id.fragment_frame, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();

            }
        });

Коли ми використовуємо add () у фрагменті

E/Keshav SecondFragment: onAttach
E/Keshav SecondFragment: onCreate
E/Keshav SecondFragment: onCreateView
E/Keshav SecondFragment: onActivityCreated
E/Keshav SecondFragment: onStart
E/Keshav SecondFragment: onResume

Коли ми використовуємо fragment () у фрагменті

перехід до першого фрагмента до другого фрагмента в Перший -> Другий за допомогою методу substitu ()

 btn_one.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(),"Click First Fragment",Toast.LENGTH_LONG).show();

                Fragment fragment = new SecondFragment();
                getActivity().getSupportFragmentManager().beginTransaction()
//                        .add(R.id.fragment_frame, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();
                        .replace(R.id.fragment_frame, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();

            }
        });

E/Keshav SecondFragment: onAttach
E/Keshav SecondFragment: onCreate

E/Keshav FirstFragment: onPause -------------------------- FirstFragment
E/Keshav FirstFragment: onStop --------------------------- FirstFragment
E/Keshav FirstFragment: onDestroyView -------------------- FirstFragment

E/Keshav SecondFragment: onCreateView
E/Keshav SecondFragment: onActivityCreated
E/Keshav SecondFragment: onStart
E/Keshav SecondFragment: onResume

У разі заміни першого фрагмента цей метод додатково викликається (onPause, onStop, onDestroyView додатково викликається)

E / Keshav FirstFragment: onPause

E / Keshav FirstFragment: onStop

E / Keshav FirstFragment: onDestroyView


0

Функція додавання та заміни FragmentManger може бути описана так: 1. означає, що вона додасть фрагмент у задній стек фрагмента, і він відобразиться в заданому кадрі, який ви надаєте як

getFragmentManager.beginTransaction.add(R.id.contentframe,Fragment1.newInstance(),null)

2.замінити означає, що ви замінюєте фрагмент іншим фрагментом у заданому кадрі

getFragmentManager.beginTransaction.replace(R.id.contentframe,Fragment1.newInstance(),null)

Основна утиліта між ними полягає в тому, що, коли ви повертаєтесь назад, укладка замінить оновить фрагмент, але додавання не оновить попередній фрагмент.


0

Важливе, що потрібно помітити:

Різниця між "Замінити" та "Замінити" за допомогою backstack - це всякий раз, коли ми використовуємо лише заміну, тоді фрагмент знищується (викликається ondestroy ()), а коли ми використовуємо заміну на backstack, тоді фрагменти onDestroy () не викликаються (тобто при натисканні кнопки "назад" фрагмент викликається з його onCreateView ())


0

Ось малюнок, який показує різницю між add()іreplace()

введіть тут опис зображення

Таким чином, add()метод продовжує додавати фрагменти зверху до попереднього фрагмента у FragmentContainer.

Хоча replace()методи очищають весь попередній фрагмент від Containers, а потім додають його в FragmentContainer.

Що таке addToBackStack

addtoBackStackметод може бути використаний з методами add () та substitution. Він виконує інше призначення в API Fragment.

Яка мета?

API фрагмента на відміну від API активності за замовчуванням не має навігаційної кнопки . Якщо ви хочете повернутися до попереднього фрагмента, тоді ми використовуємо метод addToBackStack () у фрагменті. Давайте розберемось обох

Випадок 1:

getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragmentContainer, fragment, "TAG")
            .addToBackStack("TAG")
            .commit();

введіть тут опис зображення

Випадок 2:

getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragmentContainer, fragment, "TAG")
            .commit();

введіть тут опис зображення

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