非常简单的代码,但使用Fragment时出现错误“Activity has been destroyed”。

22

我创建了一个非常简单的Activity,它展示了一个简单的ListFragment,如下所示:

我的Activity:

public class MyActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
          FragmentManager fragMgr = getSupportFragmentManager();

          FirstFragment list = new FirstFragment();
          fragMgr.beginTransaction().add(android.R.id.content, list).commit();
    }

}

我的ListFragment:

public class FirstFragment extends ListFragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        inflater.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        View view = inflater.inflate(R.layout.main, null);
        return view;
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        String listContent[] = {"Larry", "Moe", "Curly"}; 
        setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item, listContent));
    }
   ...
}

当我启动我的应用程序时,我收到了一个错误消息

 java.lang.IllegalStateException: Activity has been destroyed
E/AndroidRuntime(  947):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496)
E/AndroidRuntime(  947):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
E/AndroidRuntime(  947):    at android.app.ActivityThread.access$2200(ActivityThread.java:119)
E/AndroidRuntime(  947):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
E/AndroidRuntime(  947):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(  947):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(  947):    at android.app.ActivityThread.main(ActivityThread.java:4363)
E/AndroidRuntime(  947):    at java.lang.reflect.Method.invokeNative(Native Method)
...

它抱怨Activity已经被销毁为什么???

P.S. main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:paddingLeft="8dp"
  android:paddingRight="8dp">

  <Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="next" />

  <ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#00FF00"
    android:layout_weight="1"
    android:drawSelectorOnTop="false" />

  <TextView
    android:id="@android:id/empty"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#FF0000"
    android:text="No data" />
</LinearLayout>
9个回答

68

我也遇到了类似的问题。
我意识到这是因为在FragmentTransaction即将执行.commit()时,活动被销毁了。

解决方法是检查Activity.isFinishing()是否为真。

if (!isFinishing()) {
  FragmentTransaction ft = getSupportFragmentManager()
     .beginTransaction();
  ft.replace(SOME_RES_ID, myFragmentInstance);
  ft.commit();
}

谢谢,它对我有用!是通过Github上的讨论来到这里的。感谢分享。 - Paresh Mayani

36

我自己发现,这是因为在我的Activity的onCreate()方法中,我错过了super.onCreate(savedInstanceState);。加上之后,一切都好了。


6
如果有人能够解释深层次的原因,我会接受更好的解释而不是我的 :) - Leem.fin
1
在我的情况下,我是在添加片段后调用super.onCreate(savedInstanceState)的。 - Ankit
@lemm.fin 我正在阅读这篇文章,发现它的解释非常清晰明了。https://medium.com/@elye.project/handling-illegalstateexception-can-not-perform-this-action-after-onsaveinstancestate-d4ee8b630066 - Saurabh

12

我遇到了同样的问题,但是无法修复它。我添加了isFinishing()检查,但是没有运气。

然后我添加了一个额外的检查isDestroyed(),现在它可以正常工作了。

if (!isFinishing() && !isDestroyed()) {
  FragmentTransaction ft = getSupportFragmentManager()
     .beginTransaction();
  ft.replace(LAYOUT_ID, myFragmentInstance);
  ft.commit();
}

2
请注意,onDestroyed() 是在 API 级别 17 中添加的。 - Gira

4
为了解释一下:
该框架创建了Activity并调用Activity.onCreate()Activity.onCreate()将以某种方式连接到FragmentManager,让其了解主机活动的情况。 Activity.onDestroy()将再次注销它。
现在,您扩展了Activity并覆盖了onCreate()。 您对FragmentManager进行了调用,而没有通过Activity.onCreate()进行调用。 上述整个注册逻辑未被执行。 因此,FragmentManager不知道任何关于活动的信息,并假定它已被销毁,并生成带有误导性错误消息的异常。

3

为了确认我理解得正确,MyActivity是您试图启动并添加FirstFragment实例的活动,对吗?

我立刻看到你需要注意两件事情

1)在你的活动中你从未调用setContentView()或者super.onCreate()。 第一个调用可能会对你造成很大的问题,因为这意味着你的布局没有被膨胀,因此R变量不存在。

2)你的MyActivity需要有自己的xml布局文件,但它没有。


嗨,我认为一个Activity不一定要有一个布局文件。例如,当我添加了super.onCreate(...)后,我的代码就可以工作了。我的Activity只是托管一个Fragment,而Fragment将会填充一个布局来显示,而不是Activity。 - Leem.fin
这是可能的,因为我并没有真正多使用支持包。我的大多数开发都是在Honeycomb上使用多窗格布局。我刚刚在API文档中查看了一下,我认为你是正确的。感谢你指出这个问题! - David C. Sainte-Claire
没问题,我也是刚开始使用这个支持包,今天才开始学习 Fragment :) - Leem.fin

1

1

依然不好,因为出现了“Activity已被销毁”的错误

ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();

所以我的解决方案是添加检查if (!isFinishing()&&!isDestroyed())
 if (!isFinishing()&&!isDestroyed()) {
                        fragmentTransaction.commitAllowingStateLoss();
                    }
                }

0

super.onCreate(savedInstanceState)会调用FragmentActivity中的onCreate方法,该方法将调用mFragments.attachHost(null /*parent*/);

这个句子将为FragmentController中的mHost赋值,当您调用FragmentTransaction.commit()时。

enqueueAction()方法中,有这些句子。

 if (mDestroyed || mHost == null) {
        throw new IllegalStateException("Activity has been destroyed");
 }

所以如果在提交片段事务之前没有调用super.onCreate(savedInstanceState),您将会得到此异常,因为mHost为空。


0
如果有人遇到类似的问题:
我曾经遇到同样的问题,但是在我的情况下,我从MainActivity调用Fragment1,然后如果用户单击Fragment1布局,我想启动另一个Fragment2布局。
我能够从MainActivity启动Fragment1,但从Fragment1到Fragment2,它会失败,并显示异常"Activity已被销毁"
通过在MainActivity类中将FragmentManager对象保持为静态,我解决了上述问题。private static FragmentManager mfragmentManager = null;
使用相同的上述对象调用两个片段,解决了我的问题。
以下是我的Fragment切换代码,来自MainActivity。
public void switchToFragment(String fragmentName){
        Fragment fragment = null;
        switch (fragmentName) {
            case "Fragment1":{
                fragment = new Fragment1();
                break;
            }
            case "Fragment2": {
                fragment = new Fragment2();
                break;
            }
        }

        FragmentTransaction transaction = mfragmentManager.beginTransaction();
        transaction.replace(R.id.fragment_container, fragment);
        transaction.commit();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接