2012/03/02

ListView は Graphical Layout で作ったまま使ってはいけない

ListView の表示時に無駄が多すぎなのではないか? というエントリを書いたところ、いならさんという方からコメントをいただきました。
【Androidアプリ】AdapterのgetView()が必要以上に呼ばれる件|べっ、別にWeb言語のことなんか好きじゃないんだからねっ!!/// という記事によると、layout_width と layout_height が両方共 fill_parent じゃないと、この現象が起こるとのこと。

まさに、ご指摘の通り!
ListView の height が以下のように wrap_content になっていました。

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/listView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    </ListView>

</LinearLayout>

これを、fill_parent にすることで無駄な動きはなくなりました。
以下がログです。

Inflate 0  (position: 0)  1167910792
Display (position: 0)  1167910792
Inflate 1  (position: 1)  1167915800
Display (position: 1)  1167915800
Inflate 2  (position: 2)  1167920008
Display (position: 2)  1167920008
Inflate 3  (position: 3)  1167924216
Display (position: 3)  1167924216
Inflate 4  (position: 4)  1167928480
Display (position: 4)  1167928480
Inflate 5  (position: 5)  1167932688
Display (position: 5)  1167932688
Inflate 6  (position: 6)  1167936896
Display (position: 6)  1167936896
Inflate 7  (position: 7)  1167941104
Display (position: 7)  1167941104
Inflate 8  (position: 8)  1167945312
Display (position: 8)  1167945312
Inflate 9  (position: 9)  1167949520
Display (position: 9)  1167949520
Inflate 10  (position: 10)  1167953728
Display (position: 10)  1167953728
Inflate 11  (position: 11)  1167957936
Display (position: 11)  1167957936

見事に直っていますね。

wrap_content だと、一度描画してみないと ListView 全体のサイズがわからない。
よって、全部(仮想的に)描画してサイズを測り、画面をはみ出ることを確認した後、もう一度描画する必要がある。ということだと思われます。
言われてみると確かにそうだー。

ただ、このレイアウト、 Graphical Layout ツールを使って書いたのです。
つまり、ドラッグアンドドロップで ListView を作成して、そのまま使っているとパフォーマンスがよろしくないですよ。って事ですね。
本当に wrap_content にしたい場合を除いて、fill_parent にしてあげましょう。(あ、最近だと match_parent ですね)
んー、気を付けなければ。

てか、既に結構やっちゃってるなー…

2012/3/3 追記
検証に使用したコードを GitHub で公開しました。
以下の要領で取得することができます。
2013/10/29 追記
諸事情により、GitHub から Bitbucket に移動しました。
$ git clone https://kokufu@bitbucket.org/kokufu/ListViewExperiment.git
$ cd ListViewExperiment
$ git checkout 20120302

2 件のコメント:

匿名 さんのコメント...

listviewに表示される画像がどうしてもずれてしまって非同期処理時に起こる不具合だと思って、1日近く悩んでいましたが、原因がレイアウトだったとは。助かりました。
ありがとうございます!!

Yusuke Miura さんのコメント...

お役に立てたようで良かったです。
ただ、この Layout の問題はパフォーマンスの問題に関したものなので、「画像がどうしてもずれてしまって」の解決策にはならないような気がします。
「画像のずれ」の意味していることによるのですが、ListView をスクロールさせていった場合、同じような問題がおこったりしないでしょうか?
その場合は、以下の記事の方が参考になるかもしれません。
穀風: getView が呼ばれるタイミングと動作