layoutのinflateパフォーマンス測定

昨日このイベントに参加して、話題に上がったことがちょうど気になってたところだったのでlayoutをinflateする際のshapeによるパフォーマンスへの影響を計測してみました。ついでに気になってたincludeの計測もしてみました。
環境はエミュレータ上のAndroid4.0.3です。

shapeのパフォーマンス

backgroundで何も指定しないTextViewとshapeを指定したTextViewおよびlayer-listを指定したTextViewをそれぞれLinearLayoutに10個配置した場合と100個配置したlayoutをinflateするのにかかる時間を計測します。

shepe,layer-list

shapeとlayer-list

  • gradation.xml
<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
     android:shape="rectangle"> 
     <gradient android:startColor="#DD000000" android:endColor="#DD2ECCFA" /> 

  • gradation_layer.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item >
        <shape xmlns:android="http://schemas.android.com/apk/res/android" 
            android:shape="rectangle"> 
            <gradient android:startColor="#DD000000" android:endColor="#DD2ECCFA" />
        </shape>
    </item>
    <item >
        <shape xmlns:android="http://schemas.android.com/apk/res/android" 
            android:shape="rectangle"> 
            <gradient android:startColor="#DD000000" android:endColor="#DD2ECCFA" />
        </shape>
    </item>
    ...以下、itemを計10個繰り返し
</layer-list>
layout

TextViewを100個ベタ書きするのは面倒なのでTextView10個のレイアウトを共通要素として定義しておきます。展開先でincludeした場所の直下に配置するためmergeタグを使います。

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Text"
        ></TextView>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Text"
        ></TextView>
    ....以下TextViewを計10個繰り返し...
</merge>

shape,layerを指定する場合も同様にTextViewを10個配置したLinearLayoutを定義しておきます。TextViewの中でbackgroundを指定します。

  • text10_w_shape.xml
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Text"
        android:background="@drawable/gradation"
        ></TextView>
  • text10_w_layer.xml
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Text"
        android:background="@drawable/gradation_layer"
        ></TextView>
inflateするlayout

実際にinflateするlayoutはTextViewを10個表示するものと100こ表示するものです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <include layout="@layout/text10"/>
</LinearLayout>
  • layout100.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
    <include layout="@layout/text10"/>
</LinearLayout>

shape, layer-listを指定している場合のlayoutも同様に記述します。

javaコード

layoutをinflateの前後で時間を取得し、inflateにかかっている時間を計測します。

	long measureInflateTime(Context c, int layout) {
		long start = 0;
		long end = 0;

		start = System.currentTimeMillis();
		View.inflate(c, layout, null);
		end = System.currentTimeMillis();
		return end - start;
	}
計測結果


かなりばらつきがありますね。GCがガンガン走ってるのでその影響かなぁ。何度かやりましたが、初回のinflateがそれ以降と比べて遅いのはほぼ確実なので何かしらキャッシュされているのでしょう。

View、shapeの種類や画像を使った場合、Androidのバージョン、機種などなど影響しそうなパラメータがいっぱいあるので一般化するのは難しいですが、何もしない場合とけっこう凝った場合で、相対的には倍くらい違うかもしれないという程度でしょうか。
ちなみにViewが80個以上だとパフォーマンス的にイケてないとADTがwarningを出す(※warningの発生条件はよくわからない。今回の例でTextViewを100個並べても出なかった)ので、100 View以上というのは推奨されません。20〜30 Viewまでであればパフォーマンスの影響はあまり意識しなくても良い気がします。

includeのパフォーマンス

ついでなので、これも気になっていた includeのパフォーマンスをチェックしてみました。TextViewを直書きするかincludeするかで10個と100個の場合を比較してみました。

layout

100この時のlayoutファイルは以下の通りです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Text"
        ></TextView>
    ...以下TextViewが計100個コピペ...
</LinearLayout>
  • layout_include100.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <include layout="@layout/text1"/>
    <include layout="@layout/text1"/>
    ....以下includeを計100個
</LinearLayout>
計測結果


10回の時はincludeするとかなり遅くなってるけど100回だと最適化されてる時があるのか直書きより速い時がある、、、
includeを展開する処理の起動に数十msかかるけど処理自体は最適されてて速いのかも。気になる人はソース読んでわかったら教えてください!

計測するソースコードgithubに上げました。
https://github.com/itog/AndroidLayoutPerformance

とりあえず以上。