在使用带有ViewPager的选项卡时获取错误“Java.lang.IllegalStateException Activity已被销毁”

时间:2013-03-04 17:24:11

标签: android android-fragments android-viewpager actionbarsherlock android-nested-fragment

我有一个应用程序,它包含在制表符模式下使用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类中,onViewCreated方法在行上显示mViewPager.setAdapter(mMyFragmentPagerAdapter)。非常感谢任何帮助......谢谢。

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)

14 个答案:

答案 0 :(得分:280)

这似乎是新添加的嵌套片段支持中的一个错误。基本上,当子FragmentManager从活动中分离时,它会导致内部状态损坏。为我修复此问题的短期解决方法是将以下内容添加到您onDetach()所称Fragment的{​​{1}}个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);
    }
}

答案 1 :(得分:13)

我遇到了完全相同的问题。 我发现的唯一解决方法是每次更改标签时用新实例替换片段。

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

不是真正的解决方案,但我还没有找到重用前一个片段实例的方法......

答案 2 :(得分:7)

我在方法结束时调用super.onCreate()时遇到了同样的问题。原因是:attachActivity()在FragmentActivity的onCreate()中调用。覆盖onCreate()并且例如创建选项卡时,选项卡管理器将尝试切换到片段,而不将活动附加到FragmentManager。

简单解决方案:将调用移至super.onCreate()到函数体的头部。

一般来说,似乎有很多原因可能会出现此问题。这只是另一个......

的Matthias

答案 3 :(得分:4)

想要在我调用FragmentTransaction之前添加我的问题是在我尝试在onCreate中创建super.onCreate()的活动中。我刚刚将super.onCreate()移到了函数的顶部并且工作正常。

答案 4 :(得分:2)

我遇到了这个错误,因为我使用的是LocalBroadcastManager而且我做了:

unregisterReceiver(intentReloadFragmentReceiver);

而不是:

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

答案 5 :(得分:2)

我遇到了同样的问题,后来发现,我在FragmentActivity的super.onCreate( savedInstanceState );中错过了对onCreate()的来电。

答案 6 :(得分:1)

在片段完全初始化之前尝试访问子FragmentManager时出现了同样的错误(即附加到活动或至少调用了onCreateView())。否则,FragmentManager会被null活动初始化,导致上述异常。

答案 7 :(得分:1)

我在onPause中强制包含子片段的片段为NULL,它修复了我的问题

fragment = null;

答案 8 :(得分: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();
    }
}

答案 9 :(得分:0)

我遇到了这个问题,我无法在这里找到解决方案,所以我想分享我的解决方案以防其他人再次遇到此问题。

我有这段代码:

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

并通过删除" onDestroy();"

来解决问题
public void finishAction() {
  finish();
}

我写初始代码的原因: 我知道当你执行"完成()"活动调用" onDestroy()",但我使用线程,我想确保在开始下一个活动之前销毁所有线程,它看起来像"完成( )"并不总是立竿见影。 我需要处理/减少很多“位图”并显示大的“位图”,我正在努力改进我的应用程序中内存的使用

现在我将使用不同的方法终止线程,并且我将从" onDestroy();"执行此方法。当我认为我需要杀死所有线程时。

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

答案 10 :(得分:0)

我遇到了这个问题并意识到这是因为我在setContentView(int id)的{​​{1}} Activity

中拨打了onCreate两次

答案 11 :(得分:0)

这个让我为Xamarin疯狂。

我遇到了一个用于TabLayout WITHIN片段的ViewPager实现,它本身在DrawerLayout中实现:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

因此,您必须在 DrawerFragment 中实现以下代码。 请注意选择正确的FragmentManager-Path。因为您可能有两个不同的FragmentManager引用:

  1. Android.Support.V4.App.FragmentManager
  2. Android.App.FragmentManager
  3. - >选择你使用的那个。 如果您想使用ChildFragmentManager,您必须为ViewPager使用类声明 Android.App.FragmentManager

    <强> Android.Support.V4.App.FragmentManager

    在“主要”片段中实施以下方法 - 在此示例中: 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。

    在“主要”片段中实施以下方法 - 在此示例中: 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+"");
        }
    }
    

答案 12 :(得分:0)

该错误已在最新的androidx版本中修复。现在,著名的解决方法将导致崩溃。所以我们现在不需要它。

答案 13 :(得分:0)

我发现我有一个在后台运行的计时器。当活动被终止时,但计时器仍在运行。在计时器完成回调中,我访问片段对象来做一些工作,这是错误!!!!片段存在,但活动不存在。

如果你有定时器服务或任何后台线程,请确保不要访问片段对象。