6

As an Android developer, it bothers me not to know wether an app performance is better by declaring the layouts programmatically or by XML.

I have read this and this question on SO, but none of them answer my question:

What is more performant: writing the layouts programmatically or declaring them in xml files ?

Note that I'm only asking about performance, I don't want answers based on other factors.

Also, I'm looking for a very technical answer. If needed, please provide links to AOSP code that justifies your answer (you can assume that Android version is Marshmallow). Even better would be to point out to an experiment/paper/benchmark were the load time of a huge layout is compared using the two different ways.

Community
  • 1
  • 1
FlyingPumba
  • 1,015
  • 2
  • 15
  • 37
  • What kind of performance are you trying to achieve? The layouts are eventually compiled into code anyways so there's really no HUGE difference. – Tdorno Feb 23 '16 at 03:09
  • I'd be satisfied by comparing Activity load time, although there are some others benchmarks to measure. – FlyingPumba Feb 23 '16 at 03:10
  • @Tdorno does that mean that XML has a disadvantage because it has to be processed into code ? – FlyingPumba Feb 23 '16 at 03:32

1 Answers1

14

For most practical intents and purposes, there is no significant performance impact to either approach. It might be relevant if you needed to inflate an incredibly large number of a particular layout, at which point you might try benchmarking it yourself to see if there's any real difference, but otherwise I'd be hard-pressed to envision a scenario that results in a significant impact either way.

Suppose you have a layout:

<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>

What happens is Android compiles this file into a binary format and packages it in the APK. When you use LayoutInflater at runtime, it will load a block of this binary format into memory and parse it, and build the view hierarchy from the contents, very similar to what you would do by hand in code. That parsing is all done in native code, so it's likely much more optimized than your typical XML parsing in java.

LayoutInflater constructs the views using reflection when it encounters a tag (e.g. <Button .../>). The first time it must look up the constructor for that particular view; thereafter it will cache the constructor for faster access later.

Where you would normally call mutators like button.setText(...), button.setBackground(...), etc., typically the views call these methods on themselves during inflation. That is, the code path being traversed through the view's constructor will perform those mutations based on the attributes parsed from the binary XML format. This is because LayoutInflater uses the two-argument constructor which accepts an AttributeSet. The implication here is that when you build views by hand, some of these methods may end up getting called twice.

For example, take the Button in the sample layout above. Buttons already have a default background (how this is actually provided is itself interesting, but not very important here), so even calling the one-argument constructor with just a Context still gets you a Button with the default background. In other words, the code path includes a call to setBackground(...) (or some equivalent) with the default background image. Then later you have to call setBackground(...) yourself with the custom drawable resource named in the XML file. It's difficult to say off hand what impact this has because it really depends on the implementation of individual views and what mutations you are making.


One final thought: I have built an app in a professional environment that avoided all use of XML (as much as possible, including things other than layouts). I can tell you without hesitation that it is immensely annoying and increases development time dramatically. I'm very good at it and it still takes far longer than doing it in XML. Additionally:

  • The code tends to be extremely verbose
  • You don't get the benefit of all the tooling built around XML layouts in the IDE
  • Even without the tooling, just the XML file alone gives you a clear representation of the view hierarchy
  • You may have to know about certain idiosyncrasies of the UI framework (some of which may depend on API level)
  • It's not always possible to map an XML attribute to a corresponding mutator method in java (again sometimes depending on API level)
  • Calculating dimensions gets a lot more interesting
  • Remembering which LayoutParams to use where is great mental gymnastics

There are probably other reasons, but those are just off the top of my head. Don't get me wrong, there are plenty of times where manual manipulation of views and hierarchies is valuable, but I wouldn't substitute inflation for that.

Karakuri
  • 38,365
  • 12
  • 84
  • 104
  • good point ,agreed it is far more troublesome to do it in code – JAAD Feb 23 '16 at 05:38
  • 1
    @Karakur great answer. I coded a small experiment https://github.com/FlyingPumba/AndroidLayoutsPerformanceBenchmark and tested it on my phone (Moto G 1st gen). To load an activity with 500 TextViews inside a LinerLayout by XML takes average 541 ms. Doing the same programmatically takes average 380 ms. That's quite a difference. Could you please give an insight on why this is happening ? From what you say I'd expect the views from XML to load faster. This gap reaches out to 1 second if I increase the views number to 5000. – FlyingPumba Feb 23 '16 at 11:14
  • My thoughts here are that, even when the Inflater uses the two-argument constructor and the xml is optimized, the whole process of traversing the tree is more "expensive" than what you save up by calling this special constructors and avoiding the double call to, for example, `setBackground()`. – FlyingPumba Feb 23 '16 at 11:20
  • 2
    @FlyingPumba It's possible that using reflection to invoke the constructor (instead of just using `new`) also adds some overhead. However, I think a lot of this is really quite moot: if you're going to inflate 500 or 5000 (or more) of anything, you should be using a `RecyclerView` anyway and recycling the views. – Karakuri Feb 24 '16 at 03:30
  • @Karakuri Have you tried using Kotlin Anko layouts for the same? – Binary Baba May 06 '18 at 07:27
  • Layout inflating can cause jitter if you use it in a `ListView` or `RecyclerView`. For `RecyclerView` it only happens when layout files are inflated for the first time. – UdaraWanasinghe Jul 25 '21 at 12:53
  • I found a view compiler from android open source project which converts xml files into equivalent java classes. https://android.googlesource.com/platform/frameworks/base/+/master/startop/view_compiler/README.md – UdaraWanasinghe Jul 25 '21 at 12:55