Writing Performant Layouts
With the ever-increasing complexity of mobile applications, you would always want to avoid user reviews like “this app is janky” or “it is too slow on my device”. So today we are going to learn about how complex layouts can cause this janky behavior, how to diagnose it, and then finally some tips on writing efficient layouts.
Layouts Matter
The refresh rate of most android devices is 60fps, so we have only 1/60 = ~16 milliseconds to render a single frame to avoid any janky behavior in the app. So the optimization of even 1 millisecond can provide huge gains.
When your app processes an object for layout, the app performs the same process on all children of the layout as well. Typically, the framework executes the layout or measure stage in a single pass and quite quickly. However, some more complicated layouts may have to iterate multiple times on parts of the hierarchy that require multiple passes to resolve before ultimately positioning the elements.
Having to perform more than one layout-and-measure iteration is referred to as DOUBLE TAXATION.

Let’s take a quick look at some scenarios that lead to double taxation:
- A LinearLayout with layout_weight needs each child to be measured twice
- GridLayout with weights or fill gravity makes it lose all the pre-processing benefits
- RelativeLayout always takes at least 2 passes
Now the question arises as to why nesting of layouts is bad? Imagine having a nested layout hierarchy in a RecyclerView item; the cost now gets multiplied by the number of items and that’s what can lead to the rendering time of a frame exceeding this 16-millisecond window.
Diagnosing the problem
Here are some tools that can help you diagnose the problem:
- Layout Inspector: provides a visual representation of your layout hierarchy in the component tree that can be used to determine the depth of a particular layout, thus eliminating unnecessary parent view groups.
- Lint: comes with a bunch of useful rules that can highlight the layout issues and provide useful suggestions to fix them as well.
- Systrace: helps you to see all the processes running in the application in the form of graphs. These can guide you to the processes which are taking more than usual time to execute. For layouts, we want to make sure that the draw, traversal, measure process is completed within the 16ms window.
- Android Profiler: one of the best tools that helps you gather a lot of information about what happens in your app behind the scenes; in the form of a graphical representation along with a mapping of the time taken by various processes to finish. It also allows you to capture traces in the app, very similar to systrace. To optimize layouts, monitor the CPU usage, and look for red frames in the graph, those are the ones causing janky behavior.

Let’s take a look at a few things we can do for optimizing layouts.
Reusing layouts
Using the <include>
tag is a very common practice. However, it can lead to unnecessary nesting. Let’s see how.
Say you defined a reusable header layout and used <include> to add this layout to an activity. We achieved code readability and reusability here—great! Let’s see how the system interprets it: the compiler replaces the <include> tag with the layout file, so we get nested Constraint-Layouts in this case.

There is a very quick and simple way to avoid this nesting by using the <merge> tag. Just replace the ConstraintLayout in layout_header.xml with the <merge> tag. To see how your views would be aligned when this layout is included in a parent layout (activity_home.xml) you can use tools: parentTag attribute to specify the parent ViewGroup in which this layout would be included, that’s it! This will make the UI in the editor look like it would when included in the specified ViewGroup.