ConstraintLayout onMeasure very slow
Asked Answered
S

3

21

so I tried refactoring some of my recycler ViewHolders to ConstraintLayouts. After I did it I was shocked after what I saw. Inflating a single view takes 20x more time than usual LinearLayout. It actually skips so many frames while doing it.

EDIT: Version of constraint layout is not relevant. Tried different combinations had almost the same results.

Can any one explain why is this happening? Maybe it's not designed for such "heavy" views?

Here is a root XML that is used in ViewHolder:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:elevation="@dimen/param_2"
    android:orientation="vertical"
    android:stateListAnimator="@animator/material_selector">

    <LinearLayout
        android:id="@+id/order_view_tabs_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/param_2"
        android:padding="@dimen/param_4"
        android:background="@color/white"
        android:divider="@drawable/empty_horizontal_divider"
        android:elevation="@dimen/param_2"
        android:orientation="horizontal"
        android:showDividers="middle"
        android:visibility="gone"/>

    <include layout="@layout/order_list_item_constraint"/>

    </LinearLayout>

And here is order_list_item_constraint.xml

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/param_4"
    android:clipToPadding="false">

    <TextView
        android:id="@+id/delivery_status"
        style="@style/DefaultText.Normal"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_marginEnd="4dp"
        android:padding="4dp"
        android:background="@color/white"
        android:elevation="2dp"
        android:gravity="center_vertical"
        android:text="@string/main_swipe_list_item_info_title_delivered_time"
        app:layout_constraintEnd_toStartOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteY="4dp"/>

    <TextView
        android:id="@+id/order_list_item_order_title"
        style="@style/FullListItemInfoText"
        android:layout_width="0dp"
        android:layout_marginTop="4dp"
        android:text="@string/main_swipe_list_item_info_title_order"
        android:textColor="@color/red_900"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/delivery_status"/>

    <TextView
        android:id="@+id/order_list_item_order_id"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@+id/start_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_order_title"
        />

    <TextView
        android:id="@+id/order_list_item_price_title"
        style="@style/FullListItemInfoText"
        android:layout_width="0dp"
        android:layout_marginTop="4dp"
        android:text="@string/main_swipe_list_item_info_title_sum"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_order_id"
        />

    <TextView
        android:id="@+id/order_list_item_price"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@+id/start_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_price_title"
        />


    <TextView
        android:id="@+id/order_list_item_threshold_title"
        style="@style/FullListItemInfoText"
        android:layout_width="0dp"
        android:layout_marginTop="4dp"
        android:text="@string/order_full_list_item_threshold_value_title"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_price"
        />

    <TextView
        android:id="@+id/order_list_item_threshold_value"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@+id/start_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_threshold_title"
        />


    <TextView
        android:id="@+id/order_list_item_sl_title"
        style="@style/FullListItemInfoText"
        android:layout_width="0dp"
        android:layout_marginTop="@dimen/param_4"
        android:text="@string/main_swipe_list_item_info_title_service_level"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_threshold_value"/>


    <TextView
        android:id="@+id/order_list_item_service_level_title"
        style="@style/FullListItemInfoDetailsText"
        android:textStyle="bold"
        android:layout_width="0dp"
        android:textSize="@dimen/text_size_12"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_sl_title"/>

    <TextView
        android:id="@+id/order_list_item_service_level_try_on"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        android:textSize="@dimen/text_size_12"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_service_level_title"/>


    <TextView
        android:id="@+id/order_list_item_service_level_partial_purchase"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        android:textSize="@dimen/text_size_12"
        app:layout_constraintEnd_toEndOf="@id/mid_guideline"
        app:layout_constraintStart_toStartOf="@id/start_guideline"
        app:layout_constraintTop_toBottomOf="@+id/order_list_item_service_level_try_on"/>


    <com.express.mobile.customView.MyNetworkImageView
        android:id="@+id/order_list_item_image_map"
        android:layout_width="0dp"
        android:layout_height="144dp"
        android:elevation="2dp"
        android:scaleType="centerCrop"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/mid_guideline"
        app:layout_constraintTop_toTopOf="parent"/>

    <ImageView
        android:id="@+id/order_list_item_map_pin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingBottom="@dimen/param_30"
        android:contentDescription="@null"
        android:elevation="2dp"
        android:src="@drawable/ic_map_pin_sz_1"
        android:visibility="gone"
        app:layout_constrainedHeight="true"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="@id/order_list_item_image_map"
        app:layout_constraintEnd_toEndOf="@id/order_list_item_image_map"
        app:layout_constraintStart_toStartOf="@id/order_list_item_image_map"
        app:layout_constraintTop_toTopOf="@id/order_list_item_image_map"/>


    <include
        android:id="@+id/order_list_item_map_interval_box"
        layout="@layout/map_interval_box"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/param_48"
        app:layout_constrainedWidth="true"
        app:layout_constraintStart_toStartOf="@id/order_list_item_image_map"/>

    <TextView
        android:id="@+id/order_list_item_timer"
        style="@style/WhiteText.Large"
        android:textStyle="bold"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/order_full_list_item_delivery_status_box_borders"
        android:elevation="2dp"
        android:gravity="center"
        android:text="@string/timer_zero_time_value_text"
        android:textSize="@dimen/text_size_24"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@id/order_list_item_map_interval_box"
        app:layout_constraintEnd_toEndOf="@id/order_list_item_map_interval_box"
        app:layout_constraintStart_toStartOf="@id/order_list_item_map_interval_box"
        app:layout_constraintTop_toTopOf="@id/order_list_item_map_interval_box"/>


    <ImageView
        android:id="@+id/order_list_item_partner_icon"
        android:layout_width="@dimen/param_40"
        android:layout_height="@dimen/param_40"
        android:layout_margin="4dp"
        android:background="@drawable/order_mod_icon"
        android:backgroundTint="@color/red_800"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:scaleType="center"
        android:src="@drawable/ic_partner"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@+id/order_list_item_image_map"
        app:layout_constraintStart_toStartOf="@+id/order_list_item_image_map"/>

    <ImageView
        android:id="@+id/order_list_item_prepaid_icon"
        android:layout_width="@dimen/param_40"
        android:layout_height="@dimen/param_40"
        android:layout_margin="4dp"
        android:background="@drawable/order_mod_icon"
        android:backgroundTint="@color/green_800"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:scaleType="center"
        android:src="@drawable/ic_prepaid"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@+id/order_list_item_image_map"
        app:layout_constraintStart_toEndOf="@id/order_list_item_partner_icon"/>

    <ImageView
        android:id="@+id/order_list_item_microcredit_icon"
        android:layout_width="@dimen/param_40"
        android:layout_height="@dimen/param_40"
        android:layout_margin="4dp"
        android:background="@drawable/order_mod_icon"
        android:backgroundTint="@color/blue_grey_700"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:scaleType="center"
        android:src="@drawable/ic_microcredit"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@+id/order_list_item_image_map"
        app:layout_constraintStart_toEndOf="@id/order_list_item_prepaid_icon"/>


    <ImageView
        android:id="@+id/order_list_item_ongoing_icon"
        android:layout_width="@dimen/param_40"
        android:layout_height="@dimen/param_40"
        android:layout_margin="4dp"
        android:background="@drawable/order_mod_icon"
        android:backgroundTint="@color/colorPrimaryDark"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:scaleType="center"
        android:src="@drawable/ic_delivery_time_ongoing"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@+id/order_list_item_image_map"
        app:layout_constraintStart_toEndOf="@id/order_list_item_microcredit_icon"/>


    <TextView
        android:id="@+id/order_list_item_name"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        android:layout_height="@dimen/param_20"
        android:layout_marginTop="8dp"
        android:drawablePadding="@dimen/param_8"
        android:drawableStart="@drawable/ic_man"
        android:maxLines="1"
        app:layout_constraintEnd_toStartOf="@id/order_list_item_call_icon"
        app:layout_constraintStart_toStartOf="@id/mid_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_image_map"/>

    <TextView
        android:id="@+id/order_list_item_phone"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        android:layout_height="@dimen/param_20"
        android:layout_marginStart="@dimen/param_28"
        android:maxLines="1"
        app:layout_constraintEnd_toStartOf="@id/order_list_item_call_icon"
        app:layout_constraintStart_toStartOf="@id/mid_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_name"/>

    <ImageView
        android:id="@+id/address_icon"
        android:layout_width="@dimen/param_20"
        android:layout_height="@dimen/param_20"
        android:layout_marginTop="4dp"
        android:contentDescription="@null"
        android:src="@drawable/ic_address"
        app:layout_constraintStart_toStartOf="@id/mid_guideline"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_phone"/>

    <TextView
        android:id="@+id/order_list_item_address"
        style="@style/FullListItemInfoDetailsText"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_marginTop="4dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="4dp"
        android:minLines="2"
        app:layout_constraintEnd_toStartOf="@id/order_list_item_call_icon"
        app:layout_constraintStart_toEndOf="@id/address_icon"
        app:layout_constraintTop_toBottomOf="@id/order_list_item_phone"/>


    <ImageView
        android:id="@+id/order_list_item_call_icon"
        android:layout_width="38dp"
        android:layout_height="38dp"
        android:padding="@dimen/param_8"
        android:background="@drawable/order_mod_icon"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:src="@drawable/ic_call"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/order_list_item_name"/>


    <ImageView
        android:id="@+id/order_list_item_navigate_icon"
        android:layout_width="38dp"
        android:layout_height="38dp"
        android:padding="@dimen/param_8"
        android:background="@drawable/order_mod_icon"
        android:contentDescription="@null"
        android:elevation="@dimen/param_4"
        android:src="@drawable/ic_order_navigate"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/order_list_item_address"/>


    <android.support.constraint.Guideline
        android:id="@+id/mid_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_end="360dp"/>


    <android.support.constraint.Guideline
        android:id="@+id/start_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="4dp"
        app:layout_constraintStart_toStartOf="parent"/>


     </android.support.constraint.ConstraintLayout>

Here is proof of problem. All child views have measure times around 0.1ms HierarchyViewer

Comparing a simple LinearLayout enter image description here

EDIT2: Here is a layout version with LinearLayout's: https://pastebin.com/ZvffUHnw

Surefire answered 9/2, 2018 at 11:7 Comment(13)
I was just wondering what is all that hype about it... Looks like something something beta / not worth looking into for now.Kathie
The ConstraintLayout was designed to have a flat hyerarchy, maybe you can adjust some constraints to improve speed, but thats it.Fiveandten
Can you provide the code for the child view implementation of Liner Layout? the image you provide seems to be comparing ConstraintLayout with lots of child to a Linear Layout with two Linear Layout as child view?Spinode
You should also mention a particular version of ConstraintLayout which you are using.Errecart
@Vincent_Paing as you see it's 29 views vs. 35 views (6 more views because of layout nesting w/o ConstraintLayout)Kathie
@KęstasVenslauskas what are you using to test the speeds? I've never known how to test the speeds of layoutsGorton
@MarkO'Sullivan developer.android.com/studio/profile/hierarchy-viewer.htmlKathie
I don't think you need ConstraintLayout for something you can do with a LinearLayout. You don't provide your LinearLayout version and you don't show the layout blueprint/preview, so it's hard to say if what you're doing makes any sense with regards to layout performance. Do you expect us to imagine what the layout looks like just by reading an XML with 29 dependent views? It's not like you made it easy to preview it in a clean project.Doha
Added LinearLayout version to pastebin. Post exceeds char limit.Kathie
Thank you @KęstasVenslauskasGorton
There's a huge difference in performance between release and debuggable build - I noticed that with debuggable enabled my app is extremely slow on emulator or lower end devices, but it actually runs pretty fast when debuggable is disabled.Eon
I experience it many times, that i refactored views or created new ones with ConstraintLayout and was shocked, how slow everything was. I measured how much time two (idenical) views took from being setup (one refactored, the other without ConstraintLayout). the ConstraintLayout, was 20% slower, compared to a LinearLayout view with nested Relative- and other LinearLayouts. @Eon good input. I will check out, if that makes a difference.Haversine
I was having performance issues as well on a newly created layout, especially low end devices running older Android. Turns out constraint layouts are slow as hell, and I'm not even talking about really complex views here. I was expecting to gain performance, not loose it...Suzan
A
9

That's definitely not expected -- I'll have to investigate more to see what's causing it. Note that 1.1 beta is right now going to be slower than 1.0, all the optimizer passes aren't enabled. At first glance there's a lot of textview with 0dp width, which is pretty costly -- like with linear layout, 0dp is going to result in a double measure. E.g. instead of:

<TextView
    android:id="@+id/order_list_item_order_title"
    android:layout_width="0dp"
    android:layout_height="20dp"
    android:layout_marginTop="4dp"
    android:text="@string/main_swipe_list_item_info_title_order"
    app:layout_constraintEnd_toEndOf="@id/mid_guideline"
    app:layout_constraintStart_toStartOf="@id/start_guideline"
    app:layout_constraintTop_toBottomOf="@+id/delivery_status"/>

You could do:

<TextView
    android:id="@+id/order_list_item_order_title"
    android:layout_width="wrap_content"
    android:layout_height="20dp"
    android:layout_marginTop="4dp"
    android:text="@string/main_swipe_list_item_info_title_order"
    app:layout_constraintStart_toStartOf="@id/start_guideline"
    app:layout_constraintTop_toBottomOf="@+id/delivery_status"/>

You don't need to have both a start and end constraints here as well, as you are using guidelines.

Note that in general, HierarchyViewer isn't going to be giving you accurate measurements (that said with such a difference, something seems wrong there).

How does your com.express.mobile.customView.MyNetworkImageView custom view handles measures? as you set it to 0dp it will also be double-measured in your layout.

Finally, Could you add what's in your included layout order_list_item_map_interval_box ?

edit 1.1 beta 6 should improve performances quite a log

Avuncular answered 19/2, 2018 at 18:22 Comment(8)
Here is order_list_item_map_interval_box: pastebin.com/q04C3sT1Kathie
I tried different approaches with wrap_contents and also newer CL versions with other newer wrap options. Still same result. I'm starting to think that this also might be device related if possible?Kathie
which device / os version are you using?Avuncular
Samsung Galaxy Tab Active LTE - [T365] Android 5.1.1 gsmarena.com/samsung_galaxy_tab_active_lte-6658.phpKathie
I see a lot of improvement on my OnePlus 3. On emulator it runs smoothly (ish).Kathie
@NicolasRoard I will keep spamming you if you don't share this code! j.gifs.com/APrX7p.gif :) why your tech talk team never shares the code link of demo examples showed at tech talks?Recliner
@Recliner they never open sourced the code as they are working on making it easier to implement using MotionLayout, but you can use github.com/ibhavikmakwana/Constraint-Layout-Animations for reference..Ragsdale
@PramodGarg thanks man for responding, but people already started with CL don't want use old design! this is the problem! (P.S: I learnt CL from Rebecca's blogs, not from basic examples from Google :D )Recliner
S
2

Just tried ConstraintLayout 1.1.0-beta6 Measure times has been cut down to around 250ms. Roughly it's faster by 40% but far from being useful in my situation.

Surefire answered 26/3, 2018 at 13:20 Comment(2)
That's very odd -- I cannot replicate the issue, things are fast when trying your layout. I noticed in the layout you posted using LinearLayout you are using a custom view for the ImageView -- do you see the same large layout times if you replaces that custom view with an empty view (like, a View with plain color background, or even just a bare ImageView) ? This might be worth checking. The other thing is, you are using a ton of 0dp elements (which are double-measured), but still, it seems it shouldn't end up with 250ms. I'm also puzzled that you see different behaviors on different devices.Avuncular
checking more your XML -- it seems that, other than the double-measure, things should really be pretty fast (it mostly fully optimize in beta 6, which leaves the measure of the individual items the likely culprit). Your @+id/order_list_item_image_map is an instance of com.express.mobile.customView.MyNetworkImageView, but uses 0dp in width -- it will be measured twice. Can you check what would be the behavior in that case?Avuncular
A
2

I believe someone posted in a comment that a non-release version of the apk will run much slower. I just confirmed it on my own app. The simple page would load very slowly and a button click would run CPU usage up to 25% using a debug app. Making a release build solved the issue.

The ConstraintLayout must be communicating heavily in the background, and those logs or callbacks are probably getting stripped when running a release build. Good luck!

Acrolein answered 17/10, 2018 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.