替换Fragment时出现IllegalStateException

时间:2011-10-09 22:33:00

标签: android android-fragments

这是使用兼容包的小型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 ”的按钮,则更改会创建一个新片段并替换“ rightLand ”使用相同FragamentActivity类的另一个实例的Fragment实例。使这两个实例不同的是传递给“newInstance(int)”的参数,它基于单击的按钮。

纵向:

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

在纵向方向上,它只显示片段“ leftPort ”(与“ leftLand ”具有相同的布局),如果单击其按钮,则会启动一个Intent启动RightFragmentActivity,显示片段“ 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 ”在被替换后没有被销毁。这可能是我错误地尝试替代它的结果。

任何帮助都会非常感激。

提前致谢!

/ AngelGalindoMuñoz

2 个答案:

答案 0 :(得分:94)

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

删除或替换片段时经常出现的一个问题是尝试删除已通过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>

爪哇:

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>

爪哇:

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创建的常见难题。您可以确保以正确的方式添加片段以允许它们被删除,然后如果这不能解决问题,我们可以进一步排除故障。

答案 1 :(得分:0)

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

onClick事件上的

只是用以下方法识别方向:getResources()。getConfiguration()。orientation

并做你的事情