Android - 布局性能:程序化 vs XML

Posted

技术标签:

【中文标题】Android - 布局性能:程序化 vs XML【英文标题】:Android - Layouts performance: Programmatic vs XML 【发布时间】:2016-06-04 17:31:44 【问题描述】:

作为一名 android 开发人员,不知道是通过编程方式声明布局还是通过 XML 声明布局更好,这让我很困扰。

我已经阅读了关于 SO 的 this 和 this 问题,但他们都没有回答我的问题:

什么更高效:以编程方式编写布局或在 xml 文件中声明它们?

请注意,我只询问性能,我不想要基于其他因素的答案。

另外,我正在寻找一个非常技术性的答案。如果需要,请提供指向 AOSP 代码的链接以证明您的回答是合理的(您可以假设 Android 版本是 Marshmallow)。如果使用两种不同的方式比较 巨大 布局的加载时间,最好指出实验/论文/基准。

【问题讨论】:

你想要达到什么样的性能?无论如何,布局最终都会编译成代码,所以真的没有太大的区别。 比较 Activity 加载时间我会很满意,尽管还有其他一些基准需要衡量。 @Tdorno 这是否意味着 XML 有一个缺点,因为它必须被处理成代码? 【参考方案1】:

对于大多数实际意图和目的,这两种方法都没有显着的性能影响。如果您需要对大量特定布局进行充气,这可能是相关的,此时您可以尝试自己对其进行基准测试,看看是否有任何真正的区别,但否则我很难想象一个结果无论哪种方式都会产生重大影响。

假设你有一个布局:

<LinearLayout xmlns:android="..."
    android:layout_
    android:layout_
    android:orientation="vertical"
    ... >

    <Button
        android:id="@+id/some_button"
        android:layout_
        android:layout_
        android:background="@drawable/my_button_bg"
        android:text="Hello World" />

    <!-- other views ... -->

</LinearLayout>

Android 会将此文件编译为二进制格式并将其打包到 APK 中。当您在运行时使用LayoutInflater 时,它会将这种二进制格式的块加载到内存中并对其进行解析,并根据内容构建视图层次结构,这与您在代码中手动执行的操作非常相似。该解析全部在本机代码中完成,因此它可能比您在 java 中的典型 XML 解析优化得多。

LayoutInflater 在遇到标签时使用反射构造视图(例如&lt;Button .../&gt;)。第一次它必须查找该特定视图的构造函数;此后它将缓存构造函数以便以后更快地访问。

您通常会调用像button.setText(...)button.setBackground(...) 等的mutators,通常视图会在膨胀期间调用这些方法。也就是说,通过视图的构造函数遍历的代码路径将根据从二进制 XML 格式解析的属性执行这些更改。这是因为LayoutInflater 使用了接受AttributeSet 的两参数构造函数。这意味着当您手动构建视图时,其中一些方法可能最终会被调用两次。

例如,以上面示例布局中的按钮为例。按钮已经有一个默认背景(这实际上是如何提供的,这本身很有趣,但在这里不是很重要),所以即使只用Context 调用单参数构造函数,仍然会得到一个带有默认背景的Button。换句话说,代码路径包括使用默认背景图像对setBackground(...)(或一些等价物)的调用。然后,您必须使用 XML 文件中命名的自定义可绘制资源自己调用 setBackground(...)。很难说这会产生什么影响,因为它实际上取决于个人视图的实施以及您正在做出的突变。


最后一个想法:我在专业环境中构建了一个应用程序,避免了所有 XML 的使用(尽可能包括布局以外的东西)。我可以毫不犹豫地告诉你,这非常烦人,并且大大增加了开发时间。我非常擅长它,它仍然比在 XML 中完成它需要更长的时间。另外:

代码往往非常冗长 您不会受益于 IDE 中围绕 XML 布局构建的所有工具 即使没有工具,仅 XML 文件就可以为您提供视图层次结构的清晰表示 您可能需要了解 UI 框架的某些特质(其中一些可能取决于 API 级别) 并非总是可以将 XML 属性映射到 java 中的相应 mutator 方法(有时又取决于 API 级别) 计算尺寸变得更加有趣 记住在哪些 LayoutParams 中使用的脑力体操很棒

可能还有其他原因,但这些只是我想不到的。不要误会我的意思,很多时候手动操作视图和层次结构很有价值,但我不会用通货膨胀代替。

【讨论】:

好点,同意在代码中这样做更麻烦 @Karakur 很好的答案。我编写了一个小实验 github.com/FlyingPumba/AndroidLayoutsPerformanceBenchmark 并在我的手机(Moto G 1st gen)上进行了测试。通过 XML 在 LinerLayout 中加载具有 500 个 TextView 的活动平均需要 541 毫秒。以编程方式执行相同操作平均需要 380 毫秒。那是相当不同的。您能否解释一下为什么会这样?根据您的说法,我希望 XML 的视图加载速度更快。如果我将观看次数增加到 5000,这个差距会达到 1 秒。 我的想法是,即使 Inflater 使用双参数构造函数并且 xml 被优化,遍历树的整个过程也比你通过调用它节省的更“昂贵”特殊构造函数并避免双重调用,例如setBackground() @FlyingPumba 使用反射调用构造函数(而不仅仅是使用new)也可能会增加一些开销。但是,我认为其中很多内容确实没有实际意义:如果您要膨胀 500 或 5000(或更多)任何东西,您应该使用 RecyclerView 并回收视图。 @Karakuri 您是否尝试过同样使用 Kotlin Anko 布局?

以上是关于Android - 布局性能:程序化 vs XML的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Android之布局文件智能提示问题

Android性能优化之布局优化

Android 性能优化 四 布局优化merge标签的使用

Android 性能优化 四 布局优化merge标签的使用

Android Proguard - 如何保持仅从 XML 布局引用的 onClick 处理程序

Android性能优化—布局优化技巧