neonDion
neonDion

Reputation: 2358

Android custom view renders slowly

//How app should function I am writing an android app where I am trying to display 6 'information cards' arranged in a 2 card X 3 card grid (rows x columns) which is inside of a viewpager in my home activity. When the activity starts the user will see 6 cards arranged in a grid. They will be able use a swiping motion which will cause the original 6 cards to slide off of the screen and another 6 cards will slide onto the screen.

//Card details The cards themselves are sort of like a form in the sense that each card has the same information fields, but each card will have different information in each field (e.g. there is a textView for each card that displays the name of the card, but each card has a different name displayed in the textview). To accomplish this I have created a card class that inflates an XML layout of the card and then populates each textView, imageView, etc... with information that is custom to each card. This view is then added as a Fragments's view so each card displayed on the screen is actually a Fragment and is displayed in my 2 X 3 grid which is also a fragment which is inside of a viewpager. So, I have a card Fragments which are placed into another grid Fragment which used as a page for the ViewPager. Also, the cards are flippable so they have a front and a back. I am using a single layout file to create a front side and back side for the cards. I selectively show / hide the front layout or back layout when I want to show either the front or back of the card.

//The problem My problem is that when the app starts up there is a 6 - 10 second lag (using a Galaxy Tab 10.1 and Nexus 7) while I wait for the cards to render. All of the card data is local, so I know I am not waiting for a web service to return data, I definitely have the data on hand and ready to use. I believe that the lag time is probably due to the fact that I have to render these cards which consist of many layouts and widgets. Also, at runtime I never know how many cards I will need to render, so I am always creating instances of the card fragments programatically.

//Things I've investigated Because I am creating the cards as fragments one thing that I have tried is to replace the card fragments with different fragments that have simpler layouts. I found that the render speed increased to an acceptable level using fragments that have simpler layouts.

//My question I'm at a point where I don't really know what to try to decrease the amount of time it takes to render the screen with the cards. I am trying to make my XML layout for the cards as simple as possible, but at some point I can't simplify them anymore without compromising the design of them. I am looking for suggestions on how it might be possible to render layouts with lots of widgets without seeing the performance hit that I'm seeing. Are there any tips or tricks for rendering complex layouts? Could defining my cards completely programmatically (no XML layout) help? Any blatant errors that you can see?

Any help would be appreciated. Thanks!

//XML layout for the cards

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <RelativeLayout
        android:layout_width="257dp"
        android:layout_height="343dp"
        android:id="@+id/cardContainerRL"
        android:layout_centerInParent="true">

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/cardFrontRL">

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical"
                >

                <RelativeLayout
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:id="@+id/frontUpperRL"
                    android:layout_weight="1"
                    android:focusable="false"
                    android:background="@drawable/card_top_note">

                    <RelativeLayout
                        android:layout_width="fill_parent"
                        android:layout_height="50dp"
                        android:id="@+id/frontHeader">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="Waiting to be completed"
                            android:id="@+id/frontStatusTV"
                            android:layout_alignParentTop="false"
                            android:singleLine="false"
                            android:layout_centerInParent="true"
                            android:textSize="12dp"/>

                        <ImageView
                            android:layout_width="20dp"
                            android:layout_height="20dp"
                            android:id="@+id/frontStarIV"
                            android:src="@drawable/cool_star"
                            android:adjustViewBounds="true"
                            android:layout_toLeftOf="@+id/frontStatusTV"
                            android:layout_centerVertical="true"
                            android:longClickable="true"/>

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="1"
                            android:id="@+id/numMessagesTV"
                            android:layout_alignParentTop="true"
                            android:layout_alignParentRight="true"
                            android:layout_marginRight="2dp"/>
                    </RelativeLayout>

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Walk the Dogs Yo!"
                        android:id="@+id/frontTaskTV"
                        android:layout_below="@+id/frontHeader"
                        android:layout_marginTop="5dp"
                        android:layout_centerHorizontal="true"
                        android:textSize="22dp"/>

                </RelativeLayout>

                <RelativeLayout
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:id="@+id/frontLowerRL"
                    android:layout_weight="1"
                    android:focusableInTouchMode="true"
                    >

                    <RelativeLayout
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent"
                        android:id="@+id/imageClip"
                        android:background="@drawable/card_bottom">
                    </RelativeLayout>

                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:id="@+id/cardImageIV"
                        android:layout_marginLeft="4dp"
                        android:layout_marginRight="4dp"
                        android:layout_marginBottom="4dp"
                        android:src="@drawable/bulldog"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"/>
                </RelativeLayout>

            </LinearLayout>

            <TextView
                android:layout_width="77dp"
                android:layout_height="77dp"
                android:text="666"
                android:id="@+id/cardPointsTV"
                android:layout_centerInParent="true"
                android:singleLine="true"
                android:background="@drawable/points_circle"
                android:gravity="center_vertical|center_horizontal"
                android:textSize="24dp"
                android:textStyle="bold"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Due on Sat. Nov 13"
                android:id="@+id/frontDateTV"
                android:layout_above="@+id/cardPointsTV"
                android:layout_centerHorizontal="true"
                android:textSize="15dp"/>
        </RelativeLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical"
            android:id="@+id/cardBackLL">

            <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/backUpper"
                android:layout_weight=".65"
                android:background="@drawable/card_top">

                <RelativeLayout
                    android:layout_width="fill_parent"
                    android:layout_height="@dimen/back_header_height"
                    android:id="@+id/backHeader"
                    android:layout_alignParentTop="true"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentRight="true">

                    <ImageView
                        android:layout_width="@dimen/back_star_width"
                        android:layout_height="@dimen/back_star_width"
                        android:id="@+id/backStarIV"
                        android:layout_alignParentTop="false"
                        android:layout_alignParentLeft="false"
                        android:src="@drawable/cool_star"
                        android:scaleType="fitXY"
                        android:layout_marginLeft="@dimen/back_star_margin_left"
                        android:layout_centerVertical="true"/>

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="To be completed"
                        android:id="@+id/backStatusTV"
                        android:layout_centerVertical="true"
                        android:singleLine="false"
                        android:textSize="@dimen/back_status_font_size"
                        android:layout_marginLeft="@dimen/card_back_detail_text_margin_left"/>

                    <LinearLayout
                        android:orientation="vertical"
                        android:layout_width="wrap_content"
                        android:layout_height="fill_parent"
                        android:layout_alignParentRight="true"
                        android:layout_alignParentTop="false"
                        android:layout_alignParentBottom="false"
                        android:layout_marginRight="@dimen/card_back_points_container_margin_right">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="fill_parent"
                            android:text="POINTS"
                            android:id="@+id/POINTS"
                            android:layout_alignParentRight="true"
                            android:textSize="@dimen/back_card_points_font_size"
                            android:layout_weight="1"
                            android:gravity="bottom"/>

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="fill_parent"
                            android:text="666"
                            android:id="@+id/backPointsTV"
                            android:layout_alignParentRight="true"
                            android:textColor="@color/dark_gray"
                            android:layout_alignParentBottom="true"
                            android:textStyle="bold"
                            android:textSize="@dimen/back_card_point_value_font_size"
                            android:layout_weight="1"
                            android:gravity="top"/>
                    </LinearLayout>

                </RelativeLayout>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Walk the Dogs Yo!"
                    android:id="@+id/backTaskTV"
                    android:layout_below="@+id/backHeader"
                    android:phoneNumber="true"
                    android:textSize="@dimen/card_back_taskname_font_size"
                    android:textIsSelectable="false"
                    android:layout_marginLeft="@dimen/card_back_detail_text_margin_left"
                    android:maxLines="2"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="DUE ON"
                    android:id="@+id/dueOnTV"
                    android:layout_alignLeft="@+id/backHeader"
                    android:layout_alignParentBottom="true"
                    android:textSize="12dp"
                    android:textIsSelectable="false"
                    android:layout_marginLeft="@dimen/card_back_detail_text_margin_left"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Sun. May 14"
                    android:id="@+id/backDateTV"
                    android:textSize="12dp"
                    android:textStyle="italic"
                    android:layout_toRightOf="@+id/dueOnTV"
                    android:layout_alignTop="@+id/dueOnTV"
                    android:layout_marginLeft="4dp"
            </RelativeLayout>

            <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/backLower"
                android:layout_weight=".35"
                android:background="@drawable/card_bottom">

                <RelativeLayout
                    android:layout_width="fill_parent"
                    android:layout_height="49dp"
                    android:layout_alignParentBottom="true"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentRight="true"

                    <ImageView
                        android:layout_width="@dimen/back_button_width"
                        android:layout_height="@dimen/back_button_height"
                        android:id="@+id/backArrowIV"
                        android:layout_alignParentLeft="true"
                        android:src="@drawable/btn_back"
                        android:layout_centerVertical="true"
                        android:layout_marginRight="@dimen/arrow_button_margin_right"
                        android:scaleType="fitXY"/>

                    <view
                        android:layout_width="@dimen/back_buttons_width"
                        android:layout_height="@dimen/back_buttons_height"
                        class="com.android.ui.widgets.ActionButton"
                        android:id="@+id/editButton"
                        android:layout_centerVertical="true"
                        android:layout_alignParentRight="true"
                        android:layout_marginRight="@dimen/send_button_margin_right"/>

                    <view
                        android:layout_width="@dimen/back_buttons_width"
                        android:layout_height="@dimen/back_buttons_height"
                        class="com.android.ui.widgets.ActionButton"
                        android:id="@+id/sendMessageButton"
                        android:layout_centerVertical="true"
                        android:layout_toLeftOf="@+id/editButton"
                        android:layout_marginRight="@dimen/edit_button_margin_right"/>

                </RelativeLayout>
            </RelativeLayout>
        </LinearLayout>

    </RelativeLayout>

</RelativeLayout>

Upvotes: 0

Views: 2943

Answers (1)

Sam Aleksov
Sam Aleksov

Reputation: 1201

With no offence you really need to review your layout. Much more complicated views can be created with layouts 5-10 times lighter than this one. You have:

<RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
    <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
       <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
            <LinearLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                    <RelativeLayout"> <!--DISPATCH MEASURE LAYOUT DRAW -->
                        <TextView/> <!-- MEASURE LAYOUT DRAW -->
                        <ImageView/> <!-- MEASURE LAYOUT DRAW -->
                        <TextView/> <!-- MEASURE LAYOUT DRAW -->
                    </RelativeLayout> 
                    <TextView/> <!-- MEASURE LAYOUT DRAW -->
                </RelativeLayout>
                <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                    <RelativeLayout> <!--DISPATCH MEASURE LAYOUT DRAW -->
                    </RelativeLayout>
                    <ImageView/> <!-- MEASURE LAYOUT DRAW -->
                </RelativeLayout>
            </LinearLayout>
            <TextView/> <!-- MEASURE LAYOUT DRAW -->
            <TextView/> <!-- MEASURE LAYOUT DRAW -->
        </RelativeLayout>
        <LinearLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
           <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW-->
                    <ImageView/> <!-- MEASURE LAYOUT DRAW -->
                    <TextView/> <!-- MEASURE LAYOUT DRAW -->
                    <LinearLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                        <TextView/> <!-- MEASURE LAYOUT DRAW -->
                        <TextView/> <!-- MEASURE LAYOUT DRAW -->
                    </LinearLayout>
                </RelativeLayout>
                <TextView /> <!-- MEASURE LAYOUT DRAW -->
                <TextView /> <!-- MEASURE LAYOUT DRAW -->
                <TextView /> <!-- MEASURE LAYOUT DRAW -->
            </RelativeLayout>
            <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
               <RelativeLayout> <!-- DISPATCH MEASURE LAYOUT DRAW -->
                    <ImageView /> <!-- MEASURE LAYOUT DRAW -->
                    <view /> <!-- MEASURE LAYOUT DRAW -->
                    <view /> <!-- MEASURE LAYOUT DRAW -->
               </RelativeLayout>
            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout>
</RelativeLayout>

Even parsing this layout will take some time on small devices. And this is only for creation, I don't wanna think about dispatching touch events with a view hierarchy like this.

If you really cannot come out with a lighter layout. You can:

Cheers, Sam.

Source: Google and years of experience in Android development.

Upvotes: 2

Related Questions