Since announcing ConstraintLayout
at Google I/O last year, we've continued to improve the layout's stability and layout editor support. We've also added new features specific toConstraintLayout
that help you build various type of layouts, such as introducing chains and setting size as a ratio. In addition to these features, there is a notable performance benefit by using ConstraintLayout
. In this post, we'll walk through how you can benefit from these performance improvements.
How Android draws views?
To better understand the performance of ConstraintLayout
, let's take a step back and see how Android draws views.
When a user brings an Android view into focus, the Android framework directs the view to draw itself. This drawing process comprises 3 phases:
- Measure
The system completes a top-down traversal of the view tree to determine how large each
ViewGroup
and View element should be. When aViewGroup
is measured, it also measures its children. - Layout
Another top-down traversal occurs, with each
ViewGroup
determining the positions of its children using the sizes determined in the measure phase. - Draw
The system performs yet another top-down traversal. For each object in the view tree, a
Canvas
object is created to send a list of drawing commands to the GPU. These commands include theViewGroup
andView
objects' sizes and positions, which the system determined during the previous 2 phases.
Each phase within the drawing process requires a top-down traversal of the view tree. Therefore, the more views you embed within each other (or nest) into the view hierarchy, the more time and computation power it takes for the device to draw the views. By keeping a flat hierarchy in your Android app layouts, you can create a fast and responsive user interface for your app.
The expense of a traditional layout hierarchy
With that explanation in mind, let's create a traditional layout hierarchy that uses LinearLayout
and RelativeLayout
objects.
Let's say we want to build a layout like the image above. If you build it with traditional layouts, the XML file contains an element hierarchy similar to the following (for this example, we've omitted the attributes):
<RelativeLayout> <ImageView /> <ImageView /> <RelativeLayout> <TextView /> <LinearLayout> <TextView /> <RelativeLayout> <EditText /> </RelativeLayout> </LinearLayout> <LinearLayout> <TextView /> <RelativeLayout> <EditText /> </RelativeLayout> </LinearLayout> <TextView /> </RelativeLayout> <LinearLayout > <Button /> <Button /> </LinearLayout> </RelativeLayout>
Although there's usually room for improvement in this type of view hierarchy, you'll almost certainly still need to create a hierarchy with some nested views.
As discussed before, nested hierarchies can adversely affect performance. Let's take a look at how the nested views actually affect the UI performance using Android Studio's Systracetool. We called the measure and layout phases for each ViewGroup
(ConstraintLayout
and RelativeLayout
) programmatically and triggered Systrace while the measure and layout calls are executing. The following command generates an overview file that contains key events, such as expensive measure/layout passes, that occur during a 20-second interval:
python $ANDROID_HOME/platform-tools/systrace/systrace.py --time=20 -o ~/trace.html gfx view res
For more details about how you can use Systrace, see the Analyzing UI Performance with Systrace guide.
Systrace automatically highlights the (numerous) performance problems with this layout, as well as suggestions for fixing them. By clicking the "Alerts" tab, you will find that drawing this view hierarchy requires 80 expensive passes through the measure and layout phases!
Triggering that many expensive measure and layout phases is far from ideal; such a large amount of drawing activity could result in skipped frames that users notice. We can conclude that the layout has poor performance due to the nested hierarchy as well as the characteristic of RelativeLayout
, which measures each of its children twice.
RelativeLayout
You can check the entire code on how we performed these measurements in our GitHub repository.
The benefits of a ConstraintLayout object
If you create the same layout using ConstraintLayout
, the XML file contains an element hierarchy similar to the following (attributes again omitted):
<android.support.constraint.ConstraintLayout> <ImageView /> <ImageView /> <TextView /> <EditText /> <TextView /> <TextView /> <EditText /> <Button /> <Button /> <TextView /> </android.support.constraint.ConstraintLayout>
As this example shows, the layout now has a completely flat hierarchy. This is because ConstraintLayout
allows you to build complex layouts without having to nest View
and ViewGroup
elements.
For example, let's look at the TextView
and EditText
in the middle of the layout:
RelativeLayout
, you need to create a new
ViewGroup
to align the
EditText
vertically with the TextView:
<LinearLayout android:id="@+id/camera_area" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@id/title" > <TextView android:text="@string/camera" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:id="@+id/cameraLabel" android:labelFor="@+id/cameraType" android:layout_marginStart="16dp" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/cameraType" android:ems="10" android:inputType="textPersonName" android:text="@string/camera_value" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginTop="8dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" /> </RelativeLayout> </LinearLayout>
By using ConstraintLayout
instead, you can achieve the same effect just by adding a constraint from the baseline of the TextView
to the baseline of the EditText
without creating another ViewGroup
:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_creator="1" app:layout_constraintBaseline_creator="1" app:layout_constraintLeft_toLeftOf="@+id/activity_main_done" app:layout_constraintBaseline_toBaselineOf="@+id/cameraType" />
When running the Systrace tool for the version of our layout that uses ConstraintLayout
, you see far fewer expensive measure/layout passes during the same 20-second interval. This improvement in performance makes sense, now that we're keeping the view hierarchy flat!
ConstraintLayout
On a related note, we built the ConstraintLayout
variant of our layout using just the layout editor instead of editing the XML by hand. To achieve the same visual effect using RelativeLayout
, we probably would have needed to edit the XML by hand.
Measuring the performance difference
We analyzed how long every measure and layout pass took for two type of layouts,ConstraintLayout
and RelativeLayout
, by using OnFrameMetricsAvailableListener
, which was introduced in Android 7.0 (API level 24). This class allows you to collect frame-by-frame timing information about your app's UI rendering.
By calling the following code, you can start recording per-frame UI actions:
window.addOnFrameMetricsAvailableListener( frameMetricsAvailableListener, frameMetricsHandler);
After timing information becomes available, the app triggers theframeMetricsAvailableListener()
callback. We are interested in the measure/layout performance, so we call FrameMetrics.LAYOUT_MEASURE_DURATION
when retrieving the actual frame duration.
Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ -> val frameMetricsCopy = FrameMetrics(frameMetrics); // Layout measure duration in nanoseconds val layoutMeasureDurationNs = frameMetricsCopy.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);
To learn more about the other types of duration information that FrameMetrics
can receive, see the FrameMetrics
API reference.
Measurement results: ConstraintLayout is faster
Our performance comparison shows that ConstraintLayout
performs about 40% better in the measure/layout phase than RelativeLayout
:
As these results show, ConstraintLayout
is likely to be more performant than traditional layouts. Moreover, ConstraintLayout
has other features that help you build complex and performant layouts, as discussed in the benefits of a ConstraintLayout object section. For details, see the Build a Responsive UI with ConstraintLayout guide. We recommend that you use ConstraintLayout
when designing your app's layouts. In almost all cases when you would have previously need a deeply-nested layout, ConstraintLayout
should be your go-to layout for optimal performance and ease of use.
Appendix: Measurement environment
All the measurements above were performed in the following environment.
Device | Nexus 5X |
Android Version | 8.0 |
ConstraintLayout version | 1.0.2 |
What's next
Check out the developer guide, the API reference documentation, and the article on Mediumto fully understand what ConstraintLayout
can provide for you. And once again, thank you to all who submitted feedback and issues over the months since our alpha release of ConstraintLayout
. We're truly grateful that we were able to release the production-ready 1.0 version of ConstraintLayout
earlier this year. As we continue to improve ConstraintLayout
, please continue to send us feedback using the Android issue tracker.