为啥我们不应该将每个包含的 Android XML 布局包装在一个 <merge> 对中?

Posted

技术标签:

【中文标题】为啥我们不应该将每个包含的 Android XML 布局包装在一个 <merge> 对中?【英文标题】:Why shouldn't we wrap every included Android XML layout in a <merge> pair?为什么我们不应该将每个包含的 Android XML 布局包装在一个 <merge> 对中? 【发布时间】:2012-09-13 03:54:42 【问题描述】:

作为question 的后续行动,我想不出有什么理由不应该将每个包含的 XML 布局包装在 &lt;merge&gt; 对中。

这让我想知道,为什么 ADT 团队不将其设为默认行为?

是否存在不希望这种行为的情况?

顺便说一句,&lt;merge&gt; 标签的android documentation 中的解释比最糟糕的法律协议中的措辞还要糟糕:

&lt;merge /&gt; 标签有助于消除视图中的冗余视图组 将一个布局包含在另一个布局中时的层次结构。例如,如果 您的主要布局是垂直的LinearLayout,其中两个连续 视图可以在多个布局中重复使用,那么可重复使用的布局在 你放置的两个视图需要它自己的根视图。然而, 使用另一个 LinearLayout 作为可重用布局的根 在垂直LinearLayout 内产生垂直LinearLayout。这 嵌套的LinearLayout 除了放慢速度之外没有任何实际用途 您的 UI 性能。

罗曼,你在哪里?

【问题讨论】:

如果您不确定父视图是什么会发生什么?您将如何为您的孩子设计风格? @hwrdprkns 我不确定我是否理解你。你能举个例子吗?这听起来像是问题/评论形式的答案。通过“样式”,我假设您的意思是“决定它们应该包含在什么类型的布局中”? 呃,对不起,我不清楚。我的意思是 merge 在您不知道父 ViewGroup 是什么时没有用,因为合并不会/不能在不同的视图组之间合并。例如将 LinearLayoutFrameLayout 合并是没用的。 @hwrdprkns 也许可以,但是有什么害处吗?我认为这个标签的主要原因是防止你需要用任何类型的ViewGroup包围包含的布局文件。即使您确实在包含文件的LinearLayout 中包裹了一个包含&lt;merge/&gt; 对的包含LinearLayout,我认为它仍然会将内部LinearLayout 包含在外部文件中,对吧? 如果封闭和封闭的 ViewGroup 元素对子元素应用相同的布局参数,那么是的,自动合并将很有用。但是谁知道有些人可能已经/从代码中寻找对封闭 ViewGroup 的引用。 【参考方案1】:

include 标签的主要目的(我认为)是允许开发人员创建可重用的 xml 组件,以便在同一个活动或/和应用程序中的许多活动中多次使用。为了使该可重用组件真正有用,它需要是自包含的,并且尽可能减少外部连接。从我的角度来看,如果您要在每个包含的布局中使用 merge 标签,这将降低 include 标签的整体实用性。这是我认为会发生这种情况的一个例子:

考虑您想要实现一个可重用的ActionBar xml 组件以嵌入到您的每个活动中。它将包含一个TextView 和一个水平放置的Button。这样做的布局是:

R.layout.actionbar

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_ >

    <TextView
        android:id="@+id/actionbar_title"
        android:layout_
        android:layout_ />

    <Button
        android:id="@+id/actionbar_action"
        android:layout_
        android:layout_ />

</LinearLayout>

现在假设您的应用中有两个活动,一个是根视图是LinearLayout(垂直方向),另一个是根视图是RelativeLayout。上面的布局可以很容易地包含在LinearLayout 中(只需将其放在您想要的位置),RelativeLayout 也可以这样做,当然要考虑到 RelativeLayout 中的当前元素(请记住您必须include 标记设置layout_width/height(例如,从包含的布局的根目录复制),以便考虑其他layout_* 属性)。

现在考虑您的建议。布局将变为:

<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <TextView
        android:id="@+id/actionbar_title"
        android:layout_
        android:layout_ />

    <Button
        android:id="@+id/actionbar_action"
        android:layout_
        android:layout_ />

</merge>

查看我们的ActionBar 布局并不能告诉我们太多,您只需在某处包含TextViewButton。现在考虑根是垂直方向LinearLayout 的活动。布局R.layout.actionbar 不能简单地包含,因为这会破坏我们的ActionBar,我们需要为我们的布局添加一个额外的LinearLayout(方向为水平)以使其看起来符合需要。如您所见,您处于上述情况(没有merge 标签的布局),但是现在您必须记住将包含的布局包装在具有水平方向的LinearLayout 中,只要父根是LinearLayout方向垂直。

当根是RelativeLayout 时,情况会变得更糟,您不能简单地将include 标记与merge 一起用于RelativeLayout(阅读How to get RelativeLayout working with merge and include? 的好问题)。再次,选项是将include 嵌入到LinearLayout 中,这会使您处于没有merge 标记的情况(但现在添加的问题多于解决问题)。阅读此链接的最后一部分http://code.google.com/p/android/issues/detail?id=2863 可能会发现带有include 标签的其他错误。

从我上面的示例中可以看出,默认情况下使用merge 标签可能会在某些情况下导致一些问题。此外,当前系统代表了一种更一致的布局方式(您可以为 include 标签创建布局,就像使用根 View 创建普通布局一样)。此外,merge 标签是一种优化,我认为您不应该尝试优化,直到您开始看到一些性能问题(或者您真的想以复杂性为代价挤压每一次性能下降)。大多数应用程序在当前系统下都可以正常运行,具有相当数量视图的三四级深度布局可以在没有merge 优化的情况下完全没有问题。

merge 标签的另一个问题是,以merge 作为其根的膨胀布局需要在膨胀时将自身附加到父级。如果您要膨胀 R.layout.actionbar 布局,则必须将其附加到父级:

View actionBar = getLayoutInflater().inflate(R.layout.actionbar, root, true);

我不知道这是否是一个真正的限制,也许在极少数情况下它可能会破坏交易。

我对@9​​87654367@ - merge 对使用的看法。

【讨论】:

非常感谢您的深思熟虑的回答。我的建议是 标记始终存在 - 并不是说​​您必须像您所做的那样从包含的文件中删除 。如果您恢复它并仍然保留合并标签,您不会有想要的行为吗?附言我之前已经阅读并投票赞成相对布局问题:) @JeffAxelrod 我刚刚测试过,从我看到一个 include 标记放置在一个 RelativeLayout 中,它插入了一个根为 merge 标记的文件(它的内容是来自我的第一个R.layout.actionbar) 不起作用。此外,如果您总是添加merge 标签,这意味着LayoutInflater 在某些情况下(例如我的回答中的第一种情况)必须为无用元素(merge 标签)制作一个 xml 文件。跨度> 您在尝试此测试时是否遵循了wrapping the includes in a unique parent container 的建议?尽管即使这确实解决了问题,但我认为这种解决方法的额外ViewGroup 肯定会成为反对以这种方式做事的论据,而不是将ViewGroup 排除在包含的文件之外。对吗? @JeffAxelrod 起初我没有使用包装器ViewGroup,重要的部分是无需include 元素的包装器就可以成功(运行后也不起作用第二次测试),因为这将增加另一个额外的ViewGroup。将深度级别增加 3 只是为了在布局中插入 TextViewButton 似乎很多:)

以上是关于为啥我们不应该将每个包含的 Android XML 布局包装在一个 <merge> 对中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们在 android xml 文件中指定命名空间?

Android布局文件夹可以包含子文件夹吗?

我们是不是需要将 xmlns:android="http://schemas.android.com/apk/res/android" 添加到 XML 文件的每个根视图中?

为啥在android应用程序中解析xml时出现nullpointerexception?

为啥这个 XML 代码不为 Android 4.3 中溢出菜单的背景着色?

为啥 netconf 不使用 XML 作为数据建模语言?