【问题标题】:'IllegalStateException: Activity has been destroyed' when 'getSupportFragmentManager()' called after Activity restart'IllegalStateException: Activity 已被销毁'当 Activity 重启后调用'getSupportFragmentManager()'
【发布时间】:2013-01-25 20:23:07
【问题描述】:

我有一个包含子 ViewPager 的 ViewPager 的父 Fragment Activity。子 ViewPager 包含每个页面的片段。我使用回调接口在这些子页面片段和顶级父片段活动之间进行通信,例如

public interface Callbacks {
    public void onItemSelected(Link link);
}

在父 Fragment Activity 中,我侦听 onItemSelected 事件,例如

@Override
public void onItemSelected(Link link) {
    Bundle argumentsFront = new Bundle();
    argumentsFront.putParcelable(FragmentComments.ARG_ITEM_ID, link);
    fragmentComments = new FragmentComments();
    fragmentComments.setArguments(argumentsFront);
    getSupportFragmentManager().beginTransaction().replace(R.id.post_container, fragmentComments).commitAllowingStateLoss();
}

现在,当应用首次启动时,这可以正常工作。

如果您转动设备以更改方向,则 Activity 会重新启动。当我使用setRetainInstance(true); 时,所有片段都会自行重新初始化(我不在子 ViewPager 的页面片段中调用 setRetainInstance(true),因为它不受支持)。但是,如果我单击子 ViewPager 的片段中的列表项,则会出现此异常:

FATAL EXCEPTION: main
java.lang.IllegalStateException: Activity has been destroyed
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)

有人知道为什么会这样吗?

谢谢

【问题讨论】:

    标签: android android-fragments android-viewpager illegalstateexception


    【解决方案1】:

    我有一个类似的问题,我认为这是因为片段被保留并保留对已销毁活动的引用,我的解决方案是在活动中保留对片段的引用,例如 Fragment myfragment = null。然后在 MyFragment 中使用如下代码:

        public void onAttach(Activity activity) {
            super.onAttach(activity);
            ((TestActivity)activity).contentFragment = this;
    }
    

    【讨论】:

    • 您能否进一步解释一下,我不确定我是否完全理解。您是否保留对父片段 Activity 中每个子片段的引用?我的子片段是一个 ViewPager,其中包含许多子片段页面,所以如果我能提供帮助,我不想保留所有这些页面的静态副本。谢谢。
    【解决方案2】:

    当您旋转设备时,Android 会保存、销毁并重新创建您的 Activity 及其 ViewPagerFragments。由于ViewPager 使用您的ActivityFragmentManager,它会为您保存并重用那些Fragments(并且不会创建新的),因此它们将保留对您(现已销毁)原始@ 的旧引用987654329@,你就会得到IllegalStateException

    在您的孩子Fragments 中,尝试以下操作:

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.v(TAG, "onAttach");
    
        // Check if parent activity implements our callback interface
        if (activity != null) {
            try {
                mParentCallback = (Callbacks) activity;
            }
            catch (ClassCastException e) {
            }
        }
    }
    

    然后发生选择时:

    if(mParentCallback != null) {
        mParentCallback.onItemSelected(selectedLink);
    }
    

    由于onAttach 作为Fragment 生命周期的一部分被调用,您的Fragments 将在轮换时更新其回调引用。

    【讨论】:

    • 不幸的是,这不起作用。我的onAttach 方法已经看起来像你提供的那个。在方向更改时,我的 onAttach 方法不再被调用,因此我的回调没有被更新。父 Fragment 有setRetainInstance(true),我想这可以防止这个子 Fragment 被分离?
    • 嗯,根据文档,即使设置了setRetainInstance(true)onAttach 仍然应该被调用,所以这里可能会出现其他问题。您能否发布更多关于设置和调用回调的代码?另外,查看这个问题的答案,在这种情况下使用 setRetainInstance(true) 不是一个好习惯,您应该保存和恢复状态 - stackoverflow.com/questions/11182180/…
    • 我找到了解决方案。因为我有这样的嵌套片段:(FragmentActivity -> Fragment 1 -> Fragment 2 (with ViewPager) -> ViewPager Child Fragments) 我不得不将回调移动到 Fragment 1(其中 onAttach 和 onDetach 被调用)。然后,我从 ViewPager 的子 Fragment 中的 onItemSelected 方法对父 Fragment(Fragment 1)中的回调进行了静态调用。这似乎有点骇人听闻,但效果很好。我在片段 1 中使用setRetainInstance(true),所以子片段也保留状态。
    • 啊,我明白了,所以您的架构有点复杂。我之前做过类似的事情,Fragment 回调其父级Fragment。我在 onAttach 中使用了与上面相同的代码,但我没有将父 Activity 转换为我的回调,而是将 getParentFragment() 转换为实现回调的父 Fragment 的引用。也许这可以帮助制定更清洁的解决方案,但很高兴您找到了一种方法。
    • 非常感谢大家。起初我很困惑为什么这是公认的答案,但评论 3 和 4 有很大帮助。这就是我所拥有的:Parentfragment - >带有片段的viewpager - >子片段。我将 viewpager 片段中的侦听器放入 ParentFragment,使用 onAttach 中的 getParentFragment,然后使用第二个侦听器将 parentfragment 中的数据传递给片段活动。我想这就是史蒂文的意思。现在我可以正确地附加所有内容了:)
    【解决方案3】:

    有类似的问题。基本上,如果 ViewPager 只有几个片段,则在当前活动中存储对它们的引用。不要调用 pagerAdapter 的 getItem(),因为它会创建一个新片段并且它没有附加到任何活动,这就是我们看到“活动已被破坏”异常的原因。如果不想保留 Fragment 引用,可以使用 findViewWithTag() 方法获取 Fragment 对象。

    【讨论】:

      【解决方案4】:

      在 OnPostResume 回调中提交事务为我解决了这个问题。感谢以下博文 http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

      @Override
      protected void onPostResume() {
          super.onPostResume();
          // Commit your transactions here.
      }
      

      【讨论】:

        【解决方案5】:

        我遇到了嵌套片段的问题,并且没有一个 stackoverflow 解决方案对我有用。看起来,支持库存在一个错误,当被解雇的片段仍然存储指向先前活动的指针时(因此 getFragmentManager() 只返回 null,因为它在已经被破坏的活动上被调用),这就是您需要自己管理指针的原因。我最终得到了以下解决方案:
        1。在第一级片段中,我在方法中保存了指向活动的指针

        public void onAttach(Activity activity) {
                super.onAttach(activity);
                parentActivity = activity; // parentActivity is static variable
        }
        

        2。在处理片段的活动中,我最终得到了以下代码:

        private void launchFragment(Fragment fragment, Activity parent) {
                    FragmentTransaction transaction;
                    if(parent == null)
                        transaction = mFragmentManager.beginTransaction();
                    else    // for nested child fragments, workaround for Android parent pointer bug
                        transaction = parent.getFragmentManager().beginTransaction();
                    transaction.replace(R.id.container, fragment);
                    transaction.addToBackStack(null);
                    transaction.commit();
        }
        

        只有在调用 SECOND 级(嵌套)片段时才应该传递 FIRST 级片段的 parentActivity,因为似乎只有在您将应用从前台带入后才会出现此错误。

        【讨论】:

          猜你喜欢
          • 2016-06-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多