【问题标题】:IllegalStateException when replacing a Fragment替换片段时出现 IllegalStateException
【发布时间】:2011-10-09 22:33:00
【问题描述】:

它是使用兼容包的小型 Android 2.2 测试应用程序。这是我在收到点击时尝试替换片段的(当然是错误的)方式。我正在尝试用同一 Fragment 类的新(不同)实例替换它。正如我将解释的那样,它无法按预期工作,我需要帮助:

public class MainFragmentActivity extends FragmentActivity {
  ...

  public void myAction(View view) {
    ...
    RightFragment newRightFrag = RightFragment.newInstance(myNewOption);
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
    ft.replace(R.id.landscape_right_fragment, newRightFrag);
    ft.commit();
  }
}

你一定会看到我的错误是什么。不管怎样,让我们​​再解释一下应用程序应该做什么:

横向:

---------                ----------
| L | R |  -> click ->   | L | R2 |
---------                ----------

在横向上,活动有一个包含 2 个片段的视图:“leftLand”和“rightLand”,如果您单击片段的按钮“leftLand" 然后它会更改创建一个新的 Fragment 并将 "rightLand" Fragment 实例替换为同一 FragmentActivity 类的另一个实例。这两个实例的不同之处在于传递给“newInstance(int)”的参数,它基于单击的按钮。

纵向:

-----                  -----
|   |                  |   |
| L |   -> click ->    | R |
|   |                  |   |
-----                  -----

在纵向时,它只显示片段“leftPort”(与“leftLand”具有相同的布局),如果你点击它的按钮,它就会启动一个 Intent启动 RightFragmentActivity,显示 Fragment "rightLand"

它工作正常......如果我不替换正确的片段。如果我这样做(单击横向按钮)然后在随后的方向更改(重新启动活动)FragmentActivity 无法启动,因为像这样的“IllegalStateException: Fragment RightFragment did not create a view

D/AndroidRuntime( 1428): Shutting down VM
W/dalvikvm( 1428): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
E/AndroidRuntime( 1428): FATAL EXCEPTION: main
E/AndroidRuntime( 1428): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.agm.test/com.agm.test.MainFragmentActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
E/AndroidRuntime( 1428):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.access$2400(ActivityThread.java:125)
E/AndroidRuntime( 1428):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
E/AndroidRuntime( 1428):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 1428):        at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.main(ActivityThread.java:4627)
E/AndroidRuntime( 1428):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 1428):        at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 1428):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime( 1428):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
E/AndroidRuntime( 1428):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 1428): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
E/AndroidRuntime( 1428):        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198)
E/AndroidRuntime( 1428):        at android.app.Activity.setContentView(Activity.java:1647)
E/AndroidRuntime( 1428):        at com.agm.test.MainFragmentActivity.onCreate(MainFragmentActivity.java:25)
E/AndroidRuntime( 1428):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
E/AndroidRuntime( 1428):        ... 12 more
E/AndroidRuntime( 1428): Caused by: java.lang.IllegalStateException: Fragment com.agm.test.RightFragment did not create a view.
E/AndroidRuntime( 1428):        at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:287)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
E/AndroidRuntime( 1428):        ... 21 more
W/ActivityManager(   59):   Force finishing activity com.agm.test/.MainFragmentActivity

我意识到旧的“RightFragment”在被替换后并没有被破坏。这可能是我尝试替换它的错误方法的结果。

任何帮助将不胜感激。

提前致谢!

/安吉尔·加林多·穆尼奥斯

【问题讨论】:

  • 您的初始 RightFragment 是通过编程方式还是通过 XML 添加的?如果您尝试删除(或替换)您在 XML 中定义的片段,您可以得到into trouble
  • 感谢您这么快的回复,theisenp。我读过一些类似的文章,但我认为如果我用其他 Fragment 类的实例替换片段,它只是适用。今天下午我将尝试以编程方式进行,然后发布结果。非常感谢!
  • 我又回来了,没有运气。我正在以编程方式进行操作,在 RightFragment.onCreateView 上使用“inflater.inflate(...)”。我将视图简化为更简单的东西,但仍然失败:只是 LinearLayout 中的 TextView。看到了一些重要的东西:每次我按下一个按钮并更改 TextView 的文本它并没有完全替换它的内容,它只是在它上面绘制。它确认在“ft.replace(...)”和提交之后,原始的 RightFragment istance 永远不会被破坏。我也非常感谢至少一个链接到替换片段的正确方法。非常感谢

标签: android android-fragments


【解决方案1】:

我认为您可能误解了我的评论,因此我将在此处提供更详细的解释。

删除或替换片段通常会出现的一个问题是尝试删除已通过 XML 而不是在 Java 中以编程方式添加到布局中的片段。这与在片段的 Java 代码的 onCreateView() 函数中膨胀片段自己的布局相同(这似乎是您在回复我的评论时所描述的)。为了说明我在说什么,我将向您展示人们尝试删除/替换片段的两种方式。

这是错误的做法:

XML 布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <fragment android:name="com.example.ExampleFragment"
    android:id="@+id/example_fragment"
    android:layout_weight="1"
    android:layout_width="0dp"
    android:layout_height="match_parent" />

</LinearLayout>

Java:

swapFragment()
{
    Fragment newFragment = new ExampleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

此代码不会以您期望的方式执行。在 XML 布局中添加的初始片段不会被删除。这是因为 XML 布局旨在描述静态布局元素。你可以在运行时改变它们的内容,或者隐藏它们,但是你不能从布局中删除这些东西。这就是 Dianne Hackborn 在我之前链接的 discussion thread 中所说的。

这是正确的做法(至少根据我的经验):

XML 布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <!-- Fragment will go here eventually, but it's not added in the layout -->

</LinearLayout>

Java:

protected void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);
     setContentView(R.layout.my_layout);

     ExampleFragment newFragment = new ExampleFragment();
     FragmentTransaction transaction = getFragmentManager().beginTransaction();
     transaction.add(R.id.fragment_container, newFragment);
     transaction.commit();
}

...

swapFragment()
{
    Fragment newFragment = new ExampleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

此策略不会在初始布局中添加片段。相反,它会在创建 Activity 时将其添加到 Java 代码中。这允许它从布局中移除(使用remove()replace()

这可能无法解决您的问题,但这是 Fragments 造成的常见困难。您可以确保以正确的方式添加 Fragments 以允许它们被删除,然后如果这不能解决问题,我们可以进一步排除故障。

【讨论】:

  • 你统治!!!非常感谢,theisenp,我会邀请你喝一杯新鲜的啤酒哈哈哈 ;) 当然我误解了这一点。我会快速测试它,并会回来更新。
  • 哎呀,现在我得到一个 IllegalArgumentException: No view found for id 0x7f050006 for fragment RightFragment{44ee2af0 #3 id=0x7f050006} ,但这可能是一个完全不同的错误。我将从头开始重写它,调试代码太多,然后我会回来!但是...一个 question :视图附加到 Activity。所以在方向改变时,就像Activity被销毁一样,所有附加的Fragment都应该被运行时销毁,不是吗? / 天使加林多
  • 是的,碎片将被销毁。 Fragment 有自己的生命周期函数(如 onCreate()、onPause()、onDestryView() 等),它们会在创建或销毁它们所绑定的 Activity 时在适当的时间调用。如果重写代码不能解决您的问题,请编辑您的问题以包含您当前的代码以及您遇到的错误。从那里我们可以正确调试。
  • 我又回来了,我确认已解决!!! 非常感谢,theisenp。你帮了我很多,现在我明白了一点。这很可惜,因为我没有足够的声誉来投票给你的答案。当然其他人会这样做。现在我有点开心了 ;) 来自西班牙巴塞罗那的欢呼。 / 天使加林多
  • 太棒了,我很高兴能帮上忙!您可能没有支持答案的声誉,但您可以通过单击旁边的复选标记将其标记为已接受。这样,当其他人将来遇到这个问题时,他们可以很容易地看到我的解决方案对你有用。
【解决方案2】:

还有另一种方法,当您为大屏幕平板电脑开发应用程序时,您可以为每个屏幕方向膨胀不同的布局。您只需创建两个布局并用纵向或横向命名它们,在 onCreate 它只需膨胀xml与方向一致。

在 onClick 事件中,只需使用以下命令识别方向:getResources().getConfiguration().orientation

做你的事

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 2016-11-23
    • 1970-01-01
    相关资源
    最近更新 更多