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

Fly*_*mba 4 java xml performance android android-layout

作为一名Android开发人员,通过以编程方式或XML方式声明布局,让我不知道应用程序性能是否更好.

我已经在SO上阅读了这个这个问题,但他们都没有回答我的问题:

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

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

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

Kar*_*uri 13

对于大多数实际意图和目的,对这两种方法都没有显着的性能影响.如果你需要夸大一个特别大的特定布局,这可能是相关的,此时你可能会尝试自己进行基准测试,看看是否有任何真正的差异,但除此之外,我很难设想一个结果的场景无论如何都会产生重大影响.

假设你有一个布局:

<LinearLayout xmlns:android="..."
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    ... >

    <Button
        android:id="@+id/some_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/my_button_bg"
        android:text="Hello World" />

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

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

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

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

通常情况下button.setText(...),button.setBackground(...)在通货膨胀期间,视图会调用这些方法.也就是说,遍历视图构造函数的代码路径将根据从二进制XML格式解析的属性执行这些突变.这是因为LayoutInflater使用了接受一个的双参数构造函数AttributeSet.这里的含义是,当您手动构建视图时,其中一些方法最终可能会被调用两次.

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


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

  • 代码往往非常冗长
  • 您无法获得IDE中围绕XML布局构建的所有工具的好处
  • 即使没有工具,只需单独的XML文件就可以清晰地表示视图层次结构
  • 您可能必须了解UI框架的某些特性(其中一些可能取决于API级别)
  • 并不总是可以将XML属性映射到java中相应的mutator方法(有时还取决于API级别)
  • 计算尺寸变得更有趣
  • 记住哪些LayoutParams用于哪里是伟大的心理体操

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

  • @FlyingPumba 使用反射来调用构造函数(而不仅仅是使用`new`)也可能会增加一些开销。但是,我认为其中的很多内容都没有实际意义:如果您要膨胀 500 或 5000(或更多)任何东西,无论如何您都应该使用“RecyclerView”并回收视图。 (2认同)