Optimizing layouts with the Hierarchy Viewer

Before you can start optimizing your layouts, it helps to understand the Android layout process. Inflating a layout, begins when the activity first comes into display. Three steps occur:

  • Measure: This is where the Views determine their size, starting with the parent and working through all the children. The parent may have to call its children multiple times to work out the final size.
  • Layout: This is where the parent determines the position of its children
  • Draw: This is where the Views are actually rendered

This process starts with the parent, which then iterates through all its children. Those children iterate through their children. This creates the Layout Tree, with the parent becoming the root node in the tree.

Hierarchy Viewer is a tool included with the Android SDK for inspecting layouts. It graphically shows the Layout Tree along with timing results for each view/node. By examining the tree layout and the timing; you can look for inefficient design and bottlenecks. Armed with this information, you're in position to optimize your layouts.

For this recipe, we will use Hierarchy Viewer to inspect the example layout given in the Using RelativeLayout recipe.

Getting ready

In the There's more… section of the Using RelativeLayout recipe, a LinearLayout example was shown to highlight the difference between the layouts. The comment was made stating the LinearLayout required a nested layout. We're going to create a new project called OptimizingLayouts using the example LinearLayout. We will then use Hierarchy Viewer to inspect the layout. We will need a rooted Android device or the emulator for this Recipe.

Note

Hierarchy Viewer will only connect to rooted devices, such as an emulator.

How to do it...

  1. Open the OptimizingLayouts project in Android Studio. Run the project on your rooted device (or emulator) and make sure the screen is visible (unlock if needed).
  2. In Android Studio, start the Android Device Monitor by going to the following menu option: Tools | Android | Android Device Monitor.
  3. In Android Device Monitor, change to the Hierarchy View perspective, by going to Window | Open Perspective… this will bring up the following dialog:
  4. Now click on Hierarchy Viewer and on OK.
  5. In the Windows section on the left is the list of devices with the running processes. Click on the OptimizingLayouts process to inspect the layout.
  6. See the graphical representation of this activity in the TreeView section (in the center pane, which occupies most of the Hierarch Viewer perspective).

How it works...

The Tree Layout section shows a graphical hierarchy of the Views that comprise this layout, along with the layout times. (Unfortunately for this demonstration, the render times are too fast for visual color-coding references.) What's important for this example is the nested LinearLayouts as shown previously. (It's worth taking some time to explore the other Views that make up this layout so you can see what Android is doing for us behind the scenes.)

As already mentioned in the RelativeLayout example, the solution is to redesign this layout using the RelativeLayout. Ideally, we want a wider, flatter layout, rather than deeply nested layouts to reduce the number of iterations required during the sizing step. For timing purposes, this is obviously a trivial example, but even this example can have an impact. Imagine the user flicking through a ListView with thousands of items based on this inefficient layout. If you experience stuttering while scrolling, your optimizing steps could start by examining the layout in Hierarchy Viewer.

There's more...

Lint is another tool included with the Android SDK with built-in support by Android Studio. By default, you're already using Lint to check your code for issues such as deprecated API calls, unsupported API calls for the target API level, security issues, and so on. For our Optimizing Layout concerns, some of the conditions that Lint will automatically check include the following:

  • Deep layouts — the default maximum is 10 levels
  • Nested weights, which are bad for performance
  • Useless parent
  • Useless leaf

If you check the Lint warning in Android Studio for this layout, you will see the following warning on the second LinearLayout element:

The ViewStub can also be used to optimize a layout. Think of the ViewStub as a "lazy load" for your layout. The layout in the ViewStub will not inflate until it's needed, which reduces the Views needed to inflate. The layout will render faster and use less memory. This is a great way to have functionality that is seldom used, such as a Print feature, available when needed, but that does not take up memory when not needed. Here's an example of a ViewStub:

<ViewStub
    android:id="@+id/viewStubPrint"
    android:inflatedId="@id/print"
    android:layout="@layout/print"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

There are two ways to actually inflate the ViewStub:

  • Set the visibility parameter of ViewStub to VISIBLE:
    ((ViewStub) findViewById(R.id.viewStubPrint)).setVisibility(View.VISIBLE);
  • Call the inflate() method on the ViewStub:
    View view = ((ViewStub) findViewById(R.id.viewStubPrint)).inflate();

Once the ViewStub is inflated, the ViewStub ID will be removed from the layout and replaced with the inflated ID.