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.