作为一名Android开发人员,通过以编程方式或通过XML声明布局,我不会不知道应用程序性能是否更好。
我在SO上看过this和this问题,但没有一个回答我的问题:
什么是更高效的:以编程方式编写布局或在xml文件中声明它们?
请注意,我只询问表现,我不想根据其他因素寻求答案。
另外,我正在寻找一个非常技术性的答案。如果需要,请提供AOSP代码的链接以证明您的答案(您可以假设Android版本是Marshmallow)。更好的是指出一个实验/论文/基准是使用两种不同的方式比较巨大布局的加载时间。
答案 0 :(得分: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>
Android会将此文件编译为二进制格式并将其打包到APK中。在运行时使用LayoutInflater
时,它会将这个二进制格式的块加载到内存中并对其进行解析,并根据内容构建视图层次结构,这与您在代码中手动执行的操作非常相似。这种解析都是在本机代码中完成的,所以它可能比java中典型的XML解析更加优化。
LayoutInflater
在遇到标记时使用反射构建视图(例如<Button .../>
)。第一次必须查找该特定视图的构造函数;之后它会缓存构造函数,以便以后更快地访问。
如果您通常会调用button.setText(...)
,button.setBackground(...)
等变体,通常情况下,视图会在通胀期间调用这些方法。也就是说,遍历视图构造函数的代码路径将根据从二进制XML格式解析的属性执行这些突变。这是因为LayoutInflater
使用接受AttributeSet
的双参数构造函数。这里的含义是,当您手动构建视图时,其中一些方法最终可能会被调用两次。
例如,在上面的示例布局中选择Button。按钮已经有一个默认的背景(这实际上是如何提供它本身很有趣,但在这里不是很重要),所以即使只用一个Context
调用一个参数的构造函数仍然会得到一个Button
默认背景。换句话说,代码路径包括使用默认背景图像调用setBackground(...)
(或某些等效物)。然后,您必须使用XML文件中指定的自定义可绘制资源自行调用setBackground(...)
。现在很难说出这有什么影响,因为它实际上取决于个人观点的实施以及你正在做出的突变。
最后一个想法:我在专业环境中构建了一个应用程序,避免了所有XML的使用(尽可能多,包括布局以外的东西)。我可以毫不犹豫地告诉你它非常烦人并且大大增加了开发时间。我非常擅长它,它比用XML做的还要长。此外:
可能有其他原因,但这些只是我的头脑。不要误解我的意思,有很多时候手动操纵视图和层次结构是有价值的,但我不会用通胀代替。