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

Kęstas Venslauskas
  • 391
  • 1
  • 5
  • 14
  • I was just wondering what is all that hype about it... Looks like something something beta / not worth looking into for now. – Kęstas Venslauskas Feb 09 '18 at 12:31
  • The ConstraintLayout was designed to have a flat hyerarchy, maybe you can adjust some constraints to improve speed, but thats it. – Marcos Vasconcelos Feb 09 '18 at 12:31
  • 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? – Vincent Paing Feb 19 '18 at 09:50
  • You should also mention a particular version of ConstraintLayout which you are using. – dimsuz Feb 19 '18 at 09:51
  • 1
    @Vincent_Paing as you see it's 29 views vs. 35 views (6 more views because of layout nesting w/o ConstraintLayout) – Kęstas Venslauskas Feb 19 '18 at 10:00
  • 2
    @KęstasVenslauskas what are you using to test the speeds? I've never known how to test the speeds of layouts – Mark O'Sullivan Feb 19 '18 at 10:35
  • 2
    @MarkO'Sullivan https://developer.android.com/studio/profile/hierarchy-viewer.html – Kęstas Venslauskas Feb 19 '18 at 11:20
  • 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. – arekolek Feb 19 '18 at 12:02
  • Added LinearLayout version to pastebin. Post exceeds char limit. – Kęstas Venslauskas Feb 19 '18 at 12:39
  • Thank you @KęstasVenslauskas – Mark O'Sullivan Feb 19 '18 at 14:16
  • 1
    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. – AntekM Mar 20 '18 at 08:27
  • 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. @AntekM good input. I will check out, if that makes a difference. – Javatar Mar 20 '18 at 09:56
  • 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... – Edward van Raak May 06 '18 at 18:51

3 Answers3

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

Nicolas Roard
  • 8,339
  • 1
  • 28
  • 30
  • Here is order_list_item_map_interval_box: https://pastebin.com/q04C3sT1 – Kęstas Venslauskas Feb 20 '18 at 08:31
  • 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? – Kęstas Venslauskas Feb 20 '18 at 08:47
  • which device / os version are you using? – Nicolas Roard Feb 20 '18 at 15:15
  • Samsung Galaxy Tab Active LTE - [T365] Android 5.1.1 https://www.gsmarena.com/samsung_galaxy_tab_active_lte-6658.php – Kęstas Venslauskas Feb 20 '18 at 20:45
  • I see a lot of improvement on my OnePlus 3. On emulator it runs smoothly (ish). – Kęstas Venslauskas Feb 22 '18 at 08:09
  • @NicolasRoard I will keep spamming you if you don't share this code! https://j.gifs.com/APrX7p.gif :) why your tech talk team never shares the code link of demo examples showed at tech talks? – LOG_TAG Feb 28 '18 at 15:01
  • 1
    @LOG_TAG they never open sourced the code as they are working on making it easier to implement using MotionLayout, but you can use https://github.com/ibhavikmakwana/Constraint-Layout-Animations for reference.. – Pramod Garg Jun 06 '18 at 06:19
  • @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 ) – LOG_TAG Jun 07 '18 at 15:27
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.

Kęstas Venslauskas
  • 391
  • 1
  • 5
  • 14
  • 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. – Nicolas Roard Mar 28 '18 at 01:21
  • 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? – Nicolas Roard Mar 28 '18 at 05:14
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!

indyman777
  • 66
  • 2