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)

그래서 탭 호스트로 빌드하는 Android 앱이 있습니다. 총 3 개의 탭이 있습니다. tab2에는 tab2에서 조각 트랜잭션을 만드는 버튼이 있습니다 (조각 활동에서 함수를 호출 함).

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

다음과 같이 실행하면 예외가 있습니다.

  1. tab2 내부에서 버튼을 눌러 조각을 변경합니다.
  2. 다른 탭으로 이동 (예 : 탭 1 또는 탭 3)
  3. 뒤로 버튼 누르기
  4. 예외 발생

어떻게 고칠까요? 도움을 주셔서 감사합니다



즉, 백 프레스가 새 조각을 추가하고 있음을 의미합니다. 백 스택의 논리는 무엇입니까? 고마워요
— user782104

mFrag가 tab2와는 별도로 다른 탭에 추가됩니까?
— 아킬

답변:


152

이것은 닫히기 전에 동일한 조각 또는 DialogFragment를 두 번 추가하려고 할 때 발생합니다.

그냥 전화 해

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

그렇다고해서 이전 프래그먼트를 제거하고 동일한 프래그먼트를 다시 추가해야하는 이유는 알 수 없습니다. 단순히 프래그먼트 내부의 메서드에 매개 변수를 전달하여 UI / 데이터를 업데이트 할 수 있기 때문입니다.


5
이것은 받아 들여진 대답이어야합니다. 받아 들여진 대답은 의미가 없습니다. 첫째,의 부정이 없어야합니다 isAdded(). 둘째, 주석에서이 코드가으로 들어가는 것이 좋습니다 onCreate(). 이는 의미가 없습니다. 이 코드 라인은 단편이 추가 (또는 교체)는 라인이 아닌 직전에 배치되어야 onCreate()하거나 onCreateView(). 이러한 방법 중 하나에서 해당 코드를 실행하기에는 너무 늦었습니다.
— AndroidDev

3
if(fragment.isAdded()) fragmentTransaction.show(fragment);
— Konstantin Konopko

또한 조각을 숨기는 지 확인해야합니다.
— Mahdi Moqadasi

비슷한 조각을 추가해야하는데 조각의 속성 만 다릅니다. 그러나 중복 오류는 여전히 발생합니다.
— Alston

나는 이미 조각이 추가되었는지 확인한 다음 반환 (조각 추가 코드가 실행되지 않음)을 확인하기 위해 이미 구현했습니다. 내가 한 달 전부터 알아 내려는 모든 장치, 나는 그것을 넘을 수 없습니다, 나는 많은 솔루션을 적용하고 라이브 플레이 스토어에서 빌드를 업데이트했지만 여전히 일부 장치에서 오류가 발생합니다. 갤럭시 S20 + 5G, 화웨이, 거기에 내가 가진 문제가 적은 장치와 마찬가지로 어떤 도움 감사 감사하겠습니다
— 나빈

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를 반환하면이 메서드를 호출 할 수 없습니다." 따라서 UI를 업데이트하려면 프래그먼트 메서드를 직접 호출해야합니다.
— vovahost

예,을 통해 설정을 의미하지는 않았으며 setArguments인수를 매개 변수로 업데이트하여 보내는 것을 언급 했으므로 동일한 조각을 제거하고 추가하는 것은 사용 권한이 없습니까?
— Ujju

때에 따라 다르지. 많은 것을 재구성해야하는 경우 조각을 새 조각으로 교체하는 것이 더 쉬울 수 있습니다. 그것은 모두 당신의 필요에 달려 있습니다.
— vovahost

1
하나의 거래를 사용하면 계속 오류가 발생합니다. 아마도 이것은 Fragment Manager 작업의 비동기 동작 때문일 것입니다.
— CoolMind

8

아래에 언급 된 조각에서 하나의 조건 만 확인하면됩니다.

if(!isAdded())
{
    return;
}

i Added = 조각이 현재 활동에 추가 된 경우 true를 반환합니다. 공식 문서에서 가져 왔습니다. 이미 추가 된 경우 해당 조각을 추가하지 않습니다.

참조는 아래 링크를 확인하십시오.
http://developer.android.com/reference/android/app/Fragment.html#i Added ()


도와 주셔서 감사합니다. oncreateview 안에 if (! i added ())를 넣었나요?
— user782104

예, 위의 답변에서 언급 한 코드를 입력하면됩니다 ... 조각이 이미 스택에 추가되었음을 의미합니다. 따라서 다시 추가 할 필요가 없으며 간단히 반환됩니다.
— Deep Mehta

6
이것은 의미가 없습니다. onCreateView에서 void를 반환 할 수 없습니다. onCreate를 의미 했습니까? 난 거기에 이것을 시도하고 내 문제 도와 didnt는
— Fonix

5
이것이 추가 onCreate되었습니까?
— StuStirling 2015

5
왜 부정 부호입니까? ! i Added () 경우 조각을 추가하면 안됩니까?
— Alen Siljak

7

때로는 각 레이아웃에서 적절한 ID를 찾지 못하는 경우가 있습니다. 나는이 문제에 직면했다. 그런 다음 몇 시간 후에 잘못된 recyclerview ID를 설정했음을 발견했습니다. 나는 그것을 바꾸고 잘 작동합니다.

따라서 조각 레이아웃을 다시 확인하십시오.


2
고마워, 나도 마찬가지였다. 예외 메시지는 더 이상 오해의 소지가 없습니다.
— SqueezyMo

근본 원인을 조사한 지 한 달이 넘은 이유가 바로 이것이다. 감사합니다
— Omid Heshmatinia

7

프래그먼트 트랜잭션을 시작하기 전에 하나의 조건 만 확인하면됩니다.

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

이것은 나를 위해 perfactly 작동합니다 ...


1

FrameLayout 내의 ViewGroup 내부에 내 본문 XML을 래핑하지 않을 때이 오류가 발생합니다.

오류:

<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

@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

아니요, 대체하지 않습니다. 이전 조각을 백 스택에 추가합니다.
— M. Noman

가능할까요? 어제 참조 유사한 코드를 시도하고 오류를 가지고 stackoverflow.com/questions/38566628/...을 하기 때문에, addToBackStack함께 할 수 없습니다 commitNow.
— CoolMind

이 링크에서 그는 수동으로 백 스택을 비활성화합니다. addToBackStack로 그것은 조각의 다시 스택을 관리 할 수있게
— M.Noman

0

이것을 시도 할 수 있습니다.

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

0

다음과 같이 Fragment 내에서 ViewModel을 잘못 사용하면이 오류가 발생합니다.

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

올바른 방법 :

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

0

여기 Dialog Fragment에 대한 내 솔루션 (이 개념을 조각 클래스에도 사용할 수 있음)

버튼을 여러 번 빠르게 눌러 대화 조각 표시를 클릭하려고했습니다.

            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");
            }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.