IllegalStateException: Фрагмент, вже доданий у фрагмент вкладки


81
FATAL EXCEPTION: main
Process: com.example.loan, PID: 24169
java.lang.IllegalStateException: Fragment already added: FormFragment{428f10c8 #1 id=0x7f050055 form}
    at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1192)
    at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:722)
    at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1533)
    at android.support.v4.app.FragmentManagerImpl$2.run(FragmentManager.java:489)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5068)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
    at dalvik.system.NativeStart.main(Native Method)

Отже, у мене є андроїд-додаток, який створюється за допомогою tabhost. Всього є три вкладки, на вкладці2 є кнопка для здійснення транзакції фрагмента на вкладці2 (яка викликає функцію в дії фрагмента)

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
        t.replace(R.id.realtabcontent, mFrag);
        t.addToBackStack(null);
        t.commit();

Є виняток, якщо я запускаю так:

  1. Усередині вкладки2 я натискаю кнопку, щоб змінити фрагмент
  2. Перейдіть на іншу вкладку (наприклад, вкладку 1 або вкладку 3)
  3. Натисніть кнопку назад
  4. Киньте виняток

Як це виправити? Дякуємо за допомогу



це означає, що backpress додає новий фрагмент, яка логіка в backstack? Велике спасибі
користувач782104

mFrag додано на якусь іншу вкладку, крім tab2?
Akhil

Відповіді:


152

Це трапляється, коли ми намагаємось додати один і той же фрагмент або DialogFragment двічі перед тим, як відхилити,

просто зателефонуйте

if(mFragment.isAdded())
{
     return; //or return false/true, based on where you are calling from
}

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


5
Це має бути прийнятою відповіддю. Прийнята відповідь не має сенсу. По-перше, не повинно бути заперечення isAdded(). По-друге, у коментарях пропонується ввести цей код onCreate(), що також є безглуздим. Цей рядок коду слід розміщувати безпосередньо перед рядком, куди додається (або замінюється) фрагмент, а не в onCreate()або onCreateView(). Запізно виконувати цей код за будь-яким із цих методів.
AndroidDev

3
if(fragment.isAdded()) fragmentTransaction.show(fragment);
Костянтин Конопко

також потрібно перевірити на предмет приховування фрагментів.
Махді Мокадасі

Мені потрібно додати подібні фрагменти, і лише атрибути у фрагменті відрізняються. Але дубльована помилка все одно трапляється.
Алстон,

я вже реалізував, щоб перевірити, чи фрагмент вже додано, а потім повернено (код додавання фрагмента не буде виконаний), оскільки моє додаток працює в магазині відтворення, я все-таки отримав фрагмент аварійного завершення з деяких пристроїв, які не всі пристрої, які я намагаюся зрозуміти з місяця тому, я не можу це зробити, я застосував кілька рішень і оновив збірку в магазині живих ігор, все ще я отримую помилку від деяких пристроїв як Galaxy S20 + 5G, huawei, там менше пристроїв, які мають проблему, яку я отримав, будь-яка допомога буде вдячна спасибі
Navin

12

Видаліть старий фрагмент, якщо він все ще доданий, а потім додайте новий фрагмент:

FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("fragment_tag");
if (oldFragment != null) {
    fm.beginTransaction().remove(oldFragment).commit();
}
MyFragment newFragment = new MyFragment();
fm.beginTransaction().add(newFragment , "fragment_tag");

чи не слід надсилати аргументи для внесення змін до вже відображеного фрагмента? замість того, щоб видалити та додати його знову
Ujju,

Ви не можете встановити аргументи після того, як фрагмент був доданий до менеджера фрагментів. З документів: "Цей метод не можна викликати, якщо фрагмент додано до FragmentManager і якщо isStateSaved () поверне true." Тому вам потрібно зателефонувати до методів фрагментів безпосередньо, якщо ви хочете оновити інтерфейс.
vovahost

так, я не мав на увазі налаштування через setArguments, мав на увазі надсилання аргументів як параметрів для оновлення, тож видалення та додавання того самого фрагмента не має ніякої користі, чи не так?
Ujju

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

1
Я продовжую отримувати помилку, якщо використовую одну транзакцію. Можливо, це пов'язано з асинхронною поведінкою роботи з менеджером фрагментів.
CoolMind

8

Вам просто потрібно перевірити одну умову у вашому фрагменті, згаданому нижче:

if(!isAdded())
{
    return;
}

isAdded = Повернути true, якщо фрагмент наразі додано до своєї діяльності. Взято з офіційного документа. Це не додасть цей фрагмент, якщо він уже доданий

Перевірте посилання нижче для посилання:
http://developer.android.com/reference/android/app/Fragment.html#isAdded ()


дякую за допомогу, ви маєте на увазі, що я помістив if (! isAdded ()) всередину oncreateview?
user782104

Так, вам просто потрібно помістити той код, про який я згадав у своїй відповіді вище ... Це означає, що ваш фрагмент вже додано в стек. Отже, не потрібно додавати його знову, і він повертається просто.
Deep Mehta

6
це не має сенсу, ви не можете повернути порожнечу в onCreateView, ви мали на увазі onCreate? я спробував це там, і це не допомогло моїй проблемі
Fonix

5
Це додано до onCreate?
StuStirling

5
Чому знак заперечення? Чи не слід додавати фрагмент, якщо! IsAdded ()?
Alen Siljak

7

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

Отже, перевірте макет фрагмента.


2
Дякую, для мене було те саме. Повідомлення про виняток не може бути більш оманливим.
SqueezyMo

Після більш ніж одного місяця розслідування першопричини, це було причиною. Велике спасибі
Омід Гешматінія

7

Вам потрібно лише перевірити одну умову перед початком транзакції фрагмента

 if (!fragmentOne.isAdded()){
            transaction = manager.beginTransaction();
            transaction.add(R.id.group,fragmentOne,"Fragment_One");
            transaction.commit();
 }

це ідеально працює для мене ...


1

У мене є ця помилка, коли я не обертаю своє тіло XML усередині ViewGroup всередині FrameLayout.

Помилка:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:overScrollMode="never"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</FrameLayout>

Вирішено:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".screens.home.HomeEpoxyFragment">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv"
                android:overScrollMode="never"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

Сподіваюся, це може комусь допомогти.


0

Для мене це працює так:

Fragment oldFragment = manager.findFragmentByTag(READER_VIEW_POPUP);
if (oldFragment != null) {
    manager.beginTransaction().remove(oldFragment).commit();
}

FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();

0

Це навіть може статися, якщо FragmentStatePagerAdapterз вашого ViewPagerви створите елемент, який уже існує:

override fun getItem(position: Int): Fragment {
    return tabs[0] // Right variant: tabs[position]
}

( private val tabs: List<Fragment>це список фрагментів на вкладках).


Як ти це вирішив? Це дуже схоже на мій варіант використання
Мітч,

@Mitch, я писав return tabs[position]у другому рядку.
CoolMind

Я також використовую ту ж концепцію, return tabs[position]що і раніше, але все одно видає помилку
Мітч,

@Mitch, вибачте, я не знаю без коду. Для загального випадку в даний час я використовую stackoverflow.com/a/57161814/2914140 . Як ви думаєте, чи FragmentStatePagerAdapterвикидає помилку getItem?
CoolMind

Дуже ймовірно, що це джерело помилки, оскільки саме ViewPagerтут витягуються екземпляри (фрагменти) фрагментів, показані
Мітч,

0

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

if (!FirebaseManager.isClientA && !FirebaseManager.isClientB) {
      fragment = new FragmentA();
      getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();
} else if (FirebaseManager.isClientB) {
      fragment = new FragmentB();
} else {
      fragment = new FragmentC();
}
getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();

Переконайтесь, що не допустили тієї ж помилки.


0

Додайте фрагмент, як показано нижче

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.realtabcontent, mFrag);
    t.addToBackStack(null);
    t.commitNowAllowingStateLoss();

Що буде зі старими та новими фрагментами? Чи замінить старе новим?
CoolMind

Ні, це не замінить, він додасть попередній фрагмент у задній стек.
М.Номан

Цікаво, чи можливо це? Вчора я спробував подібну код і отримав повідомлення про помилку, див stackoverflow.com/questions/38566628 / ... , тому що addToBackStackне допускаються разом з commitNow.
CoolMind

У цьому посиланні він вручну відключає зворотний стек. За допомогою addToBackStack це дозволить управляти зворотним стеком фрагмента
M.Noman

0

Ви можете спробувати це:

 if (dialogFolderGallery.isAdded()) {
                dialogFolderGallery.dismiss();
            } else { //bla...bla..
}

0

Я отримав цю помилку при неправильному використанні мого ViewModel всередині Фрагменту, як це:

//This is wrong!
MyViewModel viewModel = new MyViewModel(getActivity().getApplication());

Правильний спосіб:

viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(MyViewModel.class);

0

Ось моє рішення для діалогового фрагмента (ви можете використовувати цю концепцію і для класу фрагментів)

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

            FragmentManager fm = getSupportFragmentManager();
            Fragment oldFragment = fm.findFragmentByTag("wait_modal");

            if(oldFragment != null && oldFragment.isAdded())
                return;

            if(oldFragment == null && !please_wait_modal.isAdded() && !please_wait_modal.isVisible()){
                fm.executePendingTransactions();
                please_wait_modal.show(fm,"wait_modal");
            }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.