替换 Fragment 时出现 IllegalStateException [英] IllegalStateException when replacing a Fragment

查看:26
本文介绍了替换 Fragment 时出现 IllegalStateException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

It's small Android 2.2 test application using the Compatibility Package. This is the (wrong, of course) way I try to replace a Fragment when receiving a click. I'm trying to replace it with a new (different) instance of the same Fragment class. As I will explain it doesn't work as expected and I need help:

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();
  }
}

你肯定已经看到我的错误了.无论如何,让我们再解释一下应用程序应该做什么:

You will surely have seen what my mistake is. Anyway let's give a little more explaination about what the application should do :

景观方向:

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

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

On landscape orientation, the activity has a view with 2 fragments: "leftLand" & "rightLand", and if you click a button of the fragment "leftLand" then it changes creates a new Fragment and substitutes the "rightLand" Fragment instance with another instance of the same FragamentActivity class. What makes different those two instances is a parameter passed to "newInstance(int)", it's based upon the clicked button.

人像方向:

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

在纵向中,它只显示片段leftPort"(与leftLand"具有相同的布局),如果您单击其按钮,则会启动一个 Intent 和启动 RightFragmentActivity,显示 Fragment "rightLand"

In portrait orientation it just shows the fragment "leftPort" (has the same layout as "leftLand") and if you click its button then it launches an Intent an starts the RightFragmentActivity, which shows the Fragment "rightLand"

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

It works fine ... if I don't replace the right fragment. If I do it (clicking the button in landscape orientation) then on a subsequent orientation change (restart of the activity) the FragmentActivity isn't able to start because of a "IllegalStateException: Fragment RightFragment did not create a view" like this :

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"在被替换后不会被破坏.这可能是我尝试替代它的错误方式的结果.

I have realized that the old "RightFragment" is not destroyed after been replaced. This is probably a consequence of my wrong way to try to substitute it.

任何帮助将不胜感激.

提前致谢!

/天使加林多·穆尼奥斯

/ Angel Galindo Muñoz

推荐答案

我想你可能误解了我的评论,所以我会在这里提供更详细的解释.

I think you may have misunderstood my comment, so I'll offer a more detailed explanation here.

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

One problem that commonly arises with removing or replacing fragments is trying to remove a fragment that has been added to the layout through XML instead of programmatically in Java. This is not the same as inflating the fragment's own layout in the onCreateView() function of the fragment's Java code (this is what you seem to be describing in your response to my comment). To illustrate what I'm talking about, I'll show you two ways that people try to remove/replace fragments.

这是错误的做法:

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 在我链接到的讨论主题中所说的之前.

This code, will not execute in the way that you expect. The initial fragment that is added in the XML layout will not be removed. This is because XML layouts are intended to describe static layout elements. You can change their contents at run time, or hide them, but you can't delete these things from the layout. This is what Dianne Hackborn was saying in the discussion thread I linked to before.

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

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())

This strategy does not add the fragment in the initial layout. Instead it adds it in the Java code when the Activity is created. This allows it to be removed from the layout (either using remove() or replace())

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

This might not solve your problem, but it is a common difficulty that Fragments create. You can make sure that you are adding the Fragments in the proper way to allow them to be removed, and then if that doesn't solve the problem we can troubleshoot further.

这篇关于替换 Fragment 时出现 IllegalStateException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆