ViewPager에서 탭을 사용할 때 "Java.lang.IllegalStateException 활동이 제거되었습니다"오류가 발생합니다.


110

탭 모드에서 ActionBarSherlock을 사용하는 애플리케이션이 있는데 5 개의 탭이 있고 각 탭의 내용은 조각을 사용하여 처리됩니다. 그러나 tab2의 경우 xml 파일에 조각 페이지가있는 ViewPager 요소가있는 조각이 있습니다. 처음 응용 프로그램을 시작할 때 응용 프로그램을 탭으로 전환 할 수 있지만 두 번째로 tab2를 누르면 위에서 언급 한 오류가 발생합니다. 주요 활동은 다음과 같습니다.

public class MainActivity extends SherlockFragmentActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();

        ActionBar.Tab tab1 = actionBar.newTab().setText("Tab1");
        ActionBar.Tab tab3 = actionBar.newTab().setText("Tab3");
        ActionBar.Tab tab2 = actionBar.newTab().setText("Tab2");
        ActionBar.Tab tab4 = actionBar.newTab().setText("Tab4");
        ActionBar.Tab tab5 = actionBar.newTab().setText("Tab5");

        Fragment fragment1 = new Tab1();
        Fragment fragment3 = new Tab3();
        Fragment fragment2 = new Tab2();
        Fragment fragment5 = new Tab5();
        Fragment fragment4 = new Tab4();

        tab1.setTabListener(new MyTabListener(fragment1));
        tab3.setTabListener(new MyTabListener(fragment3));
        tab2.setTabListener(new MyTabListener(fragment2));
        tab5.setTabListener(new MyTabListener(fragment5));
        tab4.setTabListener(new MyTabListener(fragment4));

        actionBar.addTab(tab1);
        actionBar.addTab(tab2);
        actionBar.addTab(tab3);
        actionBar.addTab(tab4);
        actionBar.addTab(tab5); 

        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    }

    class MyTabListener implements ActionBar.TabListener
    {
        Fragment fragment;

        public MyTabListener(Fragment fragment)
        {
            this.fragment = fragment;
        }

        @Override
        public void onTabSelected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {
            ft.replace(R.id.fragment_container,fragment);
        }

        @Override
        public void onTabUnselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }

        @Override
        public void onTabReselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }
    }
}

ViewPager가없는 조각 클래스는 다음과 같습니다.

public class Tab1 extends Fragment 
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.activity_tab1, container, false);
    }
}

ViewPager가있는 조각 클래스는 다음과 같습니다.

public class Tab2 extends Fragment 
{
    ViewPager mViewPager;
    private MyFragmentPagerAdapter mMyFragmentPagerAdapter;  
    private static int NUMBER_OF_PAGES = 5;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    {
        View view =  inflater.inflate(R.layout.activity_tab2, container, false); 
        return view;
    }

    @Override
    public void onViewCreated(View view,Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);
        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());  
        mViewPager.setAdapter(mMyFragmentPagerAdapter);  
    }

    private static class MyFragmentPagerAdapter extends FragmentPagerAdapter 
    {    
        public MyFragmentPagerAdapter(FragmentManager fm) 
        {  
             super(fm);  
        }  

        @Override  
        public Fragment getItem(int index) 
        {  
             return PageFragment.newInstance("My Message " + index);
        }  

        @Override  
        public int getCount() 
        {  
             return NUMBER_OF_PAGES;  
        }  
   }
}

내가 다른 곳에서 읽은 내용에서 (내가 틀렸다면 수정하십시오) 두 번째 패스의 조각 관리자가 더 이상 존재하지 않는 활동의 조각을 재사용하려고 시도하기 때문에 오류가 발생합니다. 그러나 나는 조각 활동을 사용하지 않기 때문에 왜 여기에서 일어나는지 잘 모르겠습니다. logcat에 따르면 오류는 Tab2 클래스, mViewPager.setAdapter (mMyFragmentPagerAdapter)라는 줄의 onViewCreated 메서드에 있습니다. 어떤 도움이라도 대단히 감사합니다 ... 감사합니다.

03-04 12:01:05.468: E/AndroidRuntime(2474): FATAL EXCEPTION: main
03-04 12:01:05.468: E/AndroidRuntime(2474): java.lang.IllegalStateException: Activity has been destroyed
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:1011)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:880)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:433)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.example.tabs.Tab2.onViewCreated(Tab2.java:31)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:925)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.handleCallback(Handler.java:587)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.dispatchMessage(Handler.java:92)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Looper.loop(Looper.java:123)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.app.ActivityThread.main(ActivityThread.java:3687)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invokeNative(Native Method)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invoke(Method.java:507)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at dalvik.system.NativeStart.main(Native Method)

그래서 나는 문제를 발견했을 것입니다. Eclipse 디버거를 통해 mMyFragmentPagerAdapter (class Tab2) 변수를 살펴보면, Tab2를 처음 클릭 할 때 MainActivity를 가리키는 mActivity라는 필드가있는 FragmentManager 변수가 있음을 알았습니다. 다른 탭에서 mActivity를 다시 보면 null 값이 있었는데, 이는 아마도 오류를 제공하는 이유를 설명 할 수 있습니다.
Yulric Sequeira 2013

답변:


284

이것은 중첩 된 조각에 대한 새로 추가 된 지원의 버그 인 것 같습니다. 기본적으로 자식 FragmentManager은 활동에서 분리 될 때 내부 상태가 깨집니다. 나를 위해 고친 단기 해결 방법은 호출 하는 onDetach()모든 항목에 다음을 추가 Fragment하는 것 getChildFragmentManager()입니다.

@Override
public void onDetach() {
    super.onDetach();

    try {
        Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

21
Fragment 구현을 살펴보면 분리 상태로 이동할 때 내부 상태가 재설정된다는 것을 알 수 있습니다. 그러나 mChildFragmentManager를 재설정하지는 않습니다 (현재 버전의 지원 라이브러리에있는 버그입니다). 이로 인해 조각이 다시 연결될 때 자식 조각 관리자를 다시 연결하지 않아 사용자가 본 예외가 발생합니다.
Marcus Forsell Stahre 2013

14
너 지금 농담하는 거지. 이 게시물을 발견 한 것은 다행이지만 슬픔은 좋습니다.
secureboot '2013-07-05

8
이 버그는 Android 오픈 소스 문제 추적기에서 추적되고 있습니다. code.google.com/p/android/issues/detail?id=42601
Kristopher Johnson

3
약간의 소금이지만 support-v4 버전 또는 android.app 버전을 사용하면 실패합니다. 따라서 버그는 지원 라이브러리에서만 발생하는 것이 아닙니다
gbero

6
지원 라이브러리 버전 24.0.0에서 수정 된 것 같습니다. 'android.support.v4.app.Fragment'의 'performDetach ()'메소드는 'mChildFragmentManager = null;'을 수행합니다.
Emerson Dallagnol

13

나는 똑같은 문제가 있습니다. 내가 찾은 유일한 해결 방법은 탭이 변경 될 때마다 조각을 새 인스턴스로 바꾸는 것입니다.

ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));

실제 솔루션은 아니지만 이전 조각 인스턴스를 재사용하는 방법을 찾지 못했습니다.


1
와우 감사합니다 ... 문제가 해결되었습니다. 왜 작동하는지 설명 할 수 있습니까? FragmentManager를 사용하여 오류를 수정하려고 머리가 부러졌습니다.
Yulric Sequeira 2013

1
메모리 사용량을 분석 했습니까? 이 해결 방법은 그것을 증가시킬 수 있기 때문에 적어도 나는 의심합니다
nmxprime 2014

그나마 그것이 어떻게 작동하는지 알고 works..dont 이유를 알고 있지만, 롤 작동

7

super.onCreate()내 메서드의 끝에서 호출 할 때 동일한 문제가 발생했습니다 . 이유 : attachActivity()FragmentActivity의 onCreate ()에서 호출됩니다. onCreate()예를 들어 탭을 재정의 하고 만들 때 탭 관리자는 활동이 FragmentManager에 연결되지 않은 상태에서 조각으로 전환을 시도합니다.

간단한 솔루션 : 호출을 super.onCreate()함수 본문의 헤드로 이동합니다 .

일반적으로이 문제가 발생할 수있는 많은 이유가있는 것 같습니다. 이것은 또 다른 하나입니다 ...

마티아스


대단히 감사합니다. 당신은 내 하루를 구했습니다! 저도 같은 문제를 겪고 아직도 일주 후를 해결할 수 있습니다 (그래서이 답! 썼다 매우 행복 메신저.
JonasPTFL

4

내 문제가 FragmentTransaction내가 전화하기 전에 onCreate 를 만들려고 한 활동에 있다고 추가하고 싶었습니다 super.onCreate(). 나는 방금 super.onCreate()기능의 맨 위로 이동 했고 잘 작동했습니다.


2

LocalBroadcastManager를 사용하고 있었기 때문에이 오류가 발생했습니다.

unregisterReceiver(intentReloadFragmentReceiver);

대신에:

LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);

1
이것은 내 문제를 해결하지 못합니다. 하지만 덕분에 BroadcastReceivers 사용에 대한 실수를 바로 잡는 데 도움이되었습니다
nmxprime 2014

활동 컨텍스트가 null이면 어떻게 될까요? 그렇다면 'this'는 유효하지 않습니다.
IgorGanapolsky

활동 컨텍스트가 null 일 수있는 경우 나는 결코 생각하지 않는다.
Malachiasz

2

저도 같은 문제가 발생 lateron I가 전화를 놓친 것을 발견 super.onCreate( savedInstanceState );에서 onCreate()FragmentActivity의.


1

FragmentManager조각이 완전히 초기화되기 전에 (즉, 활동에 연결되거나 적어도 onCreateView()호출 되기 전에) 자식에 액세스하려고 할 때 동일한 오류가 발생했습니다 . 그렇지 않으면 앞서 언급 한 예외를 발생시키는 활동으로 FragmentManager초기화됩니다 null.


1

onPause에서 자식 조각을 포함하는 조각을 NULL로 강제하고 내 문제를 해결합니다.

fragment = null;

1

나는 이것이 오래된 게시물이라는 것을 알고 있지만 제안 된 답변은 내 쪽에서 작동하지 않았습니다. 누군가가 유용하다고 생각할 경우를 대비하여 여기에 남겨두고 싶습니다.

내가 한 일은 :

@Override
public void onResume() {
    super.onResume();
    // add all fragments
    FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
    for(Fragment fragment : fragmentPages){
        String tag = fragment.getClass().getSimpleName();
        fragmentTransaction.add(R.id.contentPanel, fragment, tag);
        if(fragmentPages.indexOf(fragment) != currentPosition){
            fragmentTransaction.hide(fragment);
        } else {
            lastTag = tag;
        }
    }
    fragmentTransaction.commit();
}

그런 다음 :

@Override
public void onPause() {
    super.onPause();
    // remove all attached fragments
    for(Fragment fragment: fragmentPages){
        getChildFragmentManager().beginTransaction().remove(fragment).commit();
    }
}

0

이 문제가 있었는데 여기서 해결책을 찾을 수 없었기 때문에 다른 사람이이 문제를 다시 겪을 경우를 대비하여 해결책을 공유하고 싶습니다.

이 코드가 있습니다.

public void finishAction() {
  onDestroy();
  finish();
}

"onDestroy ();"줄을 삭제하여 문제를 해결했습니다.

public void finishAction() {
  finish();
}

내가 초기 코드를 작성한 이유 : "finish ()"를 실행할 때 활동이 "onDestroy ()"를 호출한다는 것을 알고 있지만 스레드를 사용하고 있으며 다음 활동을 시작하기 전에 모든 스레드가 삭제되었는지 확인하고 싶었습니다. , 그리고 "finish ()"가 항상 즉각적인 것은 아닙니다. 많은 "Bitmap"을 처리 / 축소하고 큰 "비트 맵"을 표시해야하며 앱에서 메모리 사용을 개선하기 위해 노력하고 있습니다.

이제 다른 메서드를 사용하여 스레드를 종료하고 "onDestroy ();"에서이 메서드를 실행합니다. 모든 스레드를 죽일 필요가 있다고 생각할 때.

public void finishAction() {
  onDestroyThreads();
  finish();
}

0

나는이 문제가 있었고 그것이 setContentView(int id)Activity집 에서 두 번 전화했기 때문이라는 것을 깨달았습니다.onCreate


0

이것은 나를 Xamarin에 미치게 만들었습니다.

저는 DrawerLayout에서 자체적으로 구현 된 Fragment WITHIN TabLayout에 대한 ViewPager 구현을 통해이 문제를 해결했습니다.

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

따라서 DrawerFragment에 다음 코드를 구현해야합니다 . 올바른 FragmentManager-Path를 선택해야합니다. 두 개의 다른 FragmentManager 참조가있을 수 있기 때문입니다.

  1. Android.Support.V4.App.FragmentManager
  2. Android.App.FragmentManager

-> 사용하는 것을 선택하십시오. ChildFragmentManager를 사용하려면 ViewPager에 Android.App.FragmentManager 클래스 선언을 사용해야합니다 !

Android.Support.V4.App.FragmentManager

"Main"조각에 다음 메서드를 구현합니다.이 예제에서는 DrawerFragment입니다.

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/support/v4/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

Android.App.FragmentManager

public class TabViewPager: Android.Support.V13.App.FragmentPagerAdapter {}

즉, Android.App.FragmentManager로 ViewPager를 초기화해야했습니다.

"Main"조각에 다음 메서드를 구현합니다.이 예제에서는 DrawerFragment입니다.

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

0

이 버그는 최신 androidx 버전에서 수정되었습니다. 그리고 유명한 해결 방법으로 인해 이제 충돌이 발생합니다. 그래서 지금은 필요하지 않습니다.

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