【问题标题】:Exception when inflating a layout containing fragments膨胀包含片段的布局时出现异常
【发布时间】:2012-12-21 10:31:56
【问题描述】:

我正在开发一个colour wheel app 来取乐。 0.5 版有一个由四个片段组成的调色板,一个片段用于色轮上的每个可能的颜色目标。然后根据色轮的模式隐藏或显示片段的 UI 元素。 “单色”模式只需要其中一个片段,而“Accented Anaogic”则需要全部四个。当片段被构建并显示为onCreate() 方法的一部分时,这项工作会被发现,并且此后再也不会被触及。

为了改进布局的下一个版本,我设计了四个“包含”XML 布局文件,一个只使用片段的一个实例,一个使用两个,依此类推。主 XML 布局文件现在有一个 FrameLayout 作为我在模式更改时替换适当的“包含”XML 布局文件的点。

这是执行更改的代码片段:

private void changeLayout(int layoutID) {
    FragmentManager fMgr = getFragmentManager();
    FragmentTransaction transaction = fMgr.beginTransaction();

    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    FrameLayout frame = (FrameLayout) findViewById(R.id.paletteContainer);
    frame.removeAllViews();

    View view = inflater.inflate(layoutID, frame, false);
    frame.addView(view);
    transaction.commit();

    pFrag = (SwatchFragment.Primary) fMgr.findFragmentById(R.id.base);
    a1Frag = (SwatchFragment.FirstAlternate) fMgr.findFragmentById(R.id.alternate1);
    a2Frag = (SwatchFragment.SecondAlternate) fMgr.findFragmentById(R.id.alternate2);
    cFrag = (SwatchFragment.Complementary) fMgr.findFragmentById(R.id.complementary);    
}

下面给出的例外情况是因为一个或多个片段正在被重用。那么替换包含片段的部分 UI 的正确方法是什么?

E/WheelActivityandroid.view.InflateException: Binary XML file line #11: Error inflating class Navigation item selected: pos=1, id=0x00000001
android.view.InflateException: Binary XML file line #11: Error inflating class fragment
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) ~[na:0.0]
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) ~[na:0.0]
        at android.view.LayoutInflater.inflate(LayoutInflater.java:489) ~[na:0.0]
        at android.view.LayoutInflater.inflate(LayoutInflater.java:396) ~[na:0.0]
        at org.dobbo.colour.activity.WheelActivity.changeLayout(WheelActivity.java:321) ~[na:0.0]
        at org.dobbo.colour.activity.WheelActivity.setMode(WheelActivity.java:307) ~[na:0.0]
        at org.dobbo.colour.activity.WheelActivity.onNavigationItemSelected(WheelActivity.java:181) ~[na:0.0]
        at com.android.internal.widget.ActionBarView$1.onItemSelected(ActionBarView.java:148) ~[na:0.0]
        at android.widget.AdapterView.fireOnSelected(AdapterView.java:892) ~[na:0.0]
        at android.widget.AdapterView.access$200(AdapterView.java:49) ~[na:0.0]
        at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:860) ~[na:0.0]
        at android.os.Handler.handleCallback(Handler.java:725) ~[na:0.0]
        at android.os.Handler.dispatchMessage(Handler.java:92) ~[na:0.0]
        at android.os.Looper.loop(Looper.java:137) ~[na:0.0]
        at android.app.ActivityThread.main(ActivityThread.java:5039) ~[na:0.0]
        at java.lang.reflect.Method.invokeNative(Native Method) ~[na:0.0]
        at java.lang.reflect.Method.invoke(Method.java:511) ~[na:0.0]
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) ~[na:0.0]
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) ~[na:0.0]
        at dalvik.system.NativeStart.main(Native Method) ~[na:0.0]
Caused by: java.lang.IllegalArgumentException: Binary XML file line #11: Duplicate id 0x7f0a000b, tag null, or parent id 0x7f0a0010 with anoth
er fragment for org.dobbo.colour.fragment.SwatchFragment$Primary
        at android.app.Activity.onCreateView(Activity.java:4722) ~[na:0.0]
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680) ~[na:0.0]
        ...

【问题讨论】:

    标签: android android-fragments layout-inflater


    【解决方案1】:

    下面给出的例外情况是因为一个或多个片段是 重复使用

    是的,例外来自对新布局进行膨胀,该布局具有与布局中已经存在的片段具有相同 id(很可能)的片段。为避免这种情况,您有多种选择,例如:

    您可以使用FragmentManager 查找当前存在的片段并将它们从布局中删除,然后再用片段填充新布局。例如,如果您当前的布局只有一个片段,并且您想用两个片段膨胀布局,那么您将首先删除两个布局中存在的片段:

    getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.fragment1)).commit();
    getSupportFragmentManager().executePendingTransactions();
    mContainer.removeAllViews();
    // inflate thew new layout
    

    但如果我遇到你的情况,我不会使用它(主要是因为你在搞乱静态片段,你不应该这样做)。现在,我不知道您将如何放置这些片段,但拥有一个包含占位符容器的主布局(简单@ 987654324@) 用于每个片段(所有片段都将在onCreate 方法中创建,因此您可以避免每次用户更改布局时都恢复它们)。这样,您在运行时所要做的就是隐藏所需的片段,并在必要时修改包装容器的参数。如果活动将面临配置破坏(例如旋转手机时),您还可以获得免费的片段管理(维护片段状态也很容易)。

    【讨论】:

    • 我首先要感谢@Luksporg 指出片段的静态性质。他对解决方案的建议不适合我的应用程序。我对布局的看法本质上是动态的,因此片段不是要走的路。我将片段重构为解决我的问题的视图。不过,我现在的想法是希望回到 Fragments 并使用自定义布局在各种显示模式之间进行转换。
    • @Dobbo 我对布局的看法本质上是动态的,因此片段不是要走的路。 - 我认为你误解了Fragment 框架的目的.片段不仅仅是(或)视图包装器/容器。引入它们是为了充当可重用的行为单元,开发人员可以更好地处理它。如果布局本质上是动态的,您可以使用片段,更不用说,使用它们,您可以在更大的屏幕(如平板电脑)上提供更好的用户体验。
    • @Dobbo 我做了一个小样本,随机改变了 4 个布局,这四个布局中的每一个都包含 4 个片段中的一些。你可以在这里找到它gist.github.com/4362865。您还可以查看嵌套片段。如果这没有帮助,那么也许我误解了你的问题,我会删除我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多