非常简单的代码,但是在使用 Fragment 时出现错误“活动已被破坏”
Posted
技术标签:
【中文标题】非常简单的代码,但是在使用 Fragment 时出现错误“活动已被破坏”【英文标题】:Very simple code, but got error "Activity has been destroyed" when use Fragment 【发布时间】:2012-02-26 06:29:06 【问题描述】:我制作了一个非常简单的 Activity,它显示了一个简单的 ListFragment,如下所示:
我的活动:
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已被销毁,为什么???
附: main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_
android:paddingLeft="8dp"
android:paddingRight="8dp">
<Button
android:layout_
android:layout_
android:text="next" />
<ListView
android:id="@android:id/list"
android:layout_
android:layout_
android:background="#00FF00"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
<TextView
android:id="@android:id/empty"
android:layout_
android:layout_
android:background="#FF0000"
android:text="No data" />
</LinearLayout>
【问题讨论】:
【参考方案1】: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");
所以如果你在提交 fragmentTransaction 之前没有调用 super.onCreate(savedInstanceState),你会得到这个异常,因为 mHost 为 null
【讨论】:
【参考方案2】:仍然很糟糕,因为出现错误“活动已被销毁”
ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();
所以我的解决方案是添加检查if (!isFinishing()&&!isDestroyed())
if (!isFinishing()&&!isDestroyed())
fragmentTransaction.commitAllowingStateLoss();
【讨论】:
【参考方案3】:如果有人遇到类似的问题:
我遇到了同样的问题,但在我的情况下,我是从 Main Activity 调用 Fragment1,然后如果用户单击 Fragment1 布局,我想启动另一个 Fragment2 布局。
我能够从 Main Activity 启动 Fragment1,但从 Fragment1 到 Fragment2 它失败,异常为 "Activity has been destroy" 。
我通过在 MainActivity 类中将 FragmentManager 对象保持为静态来解决上述问题。 私有静态 FragmentManager mfragmentManager = null;
使用上述相同的对象调用两个片段,解决了我的问题。
下面是我在 Main Activity 中的 Fragment 切换代码。
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();
【讨论】:
【参考方案4】:我遇到了同样的问题,无法解决。 事件我也添加了 isFinishing() 检查。但没有运气。
然后我又添加了一个检查 isDestroyed() 并且它现在可以正常工作了。
if (!isFinishing() && !isDestroyed())
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.replace(LAYOUT_ID, myFragmentInstance);
ft.commit();
【讨论】:
请注意,onDestroyed()
是在 API 级别 17 中添加的。【参考方案5】:
我所做的是在提交后立即调用
fragmentManager.executePendingTransactions();
并且在调用onpause()
之后永远不要尝试提交
阅读这篇文章Fragment Transactions & Activity State Loss
【讨论】:
【参考方案6】:我也遇到过类似的问题。
我意识到这是因为活动在FragmentTransaction
即将获得.commit()
时被破坏。
对此的解决方案是检查Activity.isFinishing()
是否为真。
if (!isFinishing())
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.replace(SOME_RES_ID, myFragmentInstance);
ft.commit();
【讨论】:
感谢它对我有用!通过discussion over Github 来到这里。感谢分享。【参考方案7】:解释一下:
框架创建Activity
并调用Activity.onCreate()
。
Activity.onCreate()
会以某种方式附加到FragmentManager
以告知其托管活动。 Activity.onDestroy()
将再次取消注册。
现在,您扩展 Activity
并覆盖 onCreate()
。您拨打FragmentManager
而不拨打Activity.onCreate()
。上面解释的整个注册逻辑没有被执行。 FragmentManager
因此对活动一无所知,并假定它已被销毁并生成带有误导性错误消息的异常。
【讨论】:
【参考方案8】:为了确保我没看错,MyActivity 是您尝试启动然后添加 FirstFragment 实例的活动,对吗?
我立刻看到了两件你需要看的东西
1) 在您的活动中,您永远不会调用 setContentView() 或 super.onCreate()。第一次调用对您来说可能是个大问题,因为这意味着您的布局从未膨胀,因此 R 变量不存在
2) 您的 MyActivity 需要有自己的 xml 布局文件,而它没有。
【讨论】:
嗨,我不认为一个 Activity 必须有一个布局文件,例如,我的代码在我添加 super.onCreate(...) 后工作,我的 Activity 只是托管一个 Fragment,并且Fragment 将膨胀一个布局来显示,而不是 Activity。 这是可能的,因为我没有真正使用过支持包。我的大部分开发都是在使用多窗格布局的 Honeycomb 上进行的。我只是在查看 API 文档,我认为您是对的。感谢您指出这一点! 没问题,我也是刚接触support包,从今天开始学习fragment :)【参考方案9】:我自己想通了,这是因为我在我的 Activity onCreate() 方法中错过了super.onCreate(savedInstanceState);
。添加后,一切都很好。
【讨论】:
如果有人能解释深层原因,我会接受更好的不是我的:) 就我而言,我正在调用 super.onCreate(savedInstanceState);添加片段后。 @lemm.fin 我正在阅读这篇文章,发现那里的解释很好。 medium.com/@elye.project/…以上是关于非常简单的代码,但是在使用 Fragment 时出现错误“活动已被破坏”的主要内容,如果未能解决你的问题,请参考以下文章
Android 在Fragment中执行onActivityResult不被调用的简单解决方法
过时的PreferenceActivity导致Fragment显示问题