【问题标题】:Very simple code, but got error "Activity has been destroyed" when use Fragment非常简单的代码,但是在使用 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_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>

【问题讨论】:

    标签: android android-layout android-emulator android-intent android-widget


    【解决方案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()&amp;&amp;!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();
            }
            

            【讨论】:

            【解决方案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/…
              猜你喜欢
              • 2018-06-08
              • 1970-01-01
              • 2015-06-01
              • 2017-01-22
              • 1970-01-01
              • 1970-01-01
              • 2013-02-18
              相关资源
              最近更新 更多