ListViewで表示される分だけデータをロードする


以前の記事でも紹介しているようにListViewでは文字や画像を表示することができます。

しかし、Adapterを単純にListViewに設定してしまうと1度に画面に表示できないデータも
ロードしてしまうため、データの数が多い場合はデータのロードに時間がかかってしまいます。

通常、1画面に表示できるデータは限られていますので、
表示できる分だけデータをロードすれば不要なデータはロードする必要がなくなり、
ロード時間を短縮することができます。

詳細な説明は続きをご覧下さい。

ポイントは画面に表示するべきデータ数だけをロードして、
画面がスクロールしたら必要なデータだけをロードすることです。
これを実現するためには画面のスクロールを検知する必要があります。
ListViewの基本的な使い方については「リストビューを使ってデータを一覧表示する」をご覧下さい。

ListView.OnScrollListener

ListView.OnScrollListenerを使うことで、
ListViewのスクロール状態を検知できるので、
スクロールしたときに表示するべきデータを選別できるようにします。

まず、クラスにListView.OnScrollListenerインタフェースを実装します。

1
public class slowLoadList extends ListActivity implements ListView.OnScrollListener

次にonScrollStateChangedメソッドをオーバーライドします。
onScrollStateChangedメソッドはスクロールの状態を検知するためのメソッドです。
以下のようにスクロール中と画面をはじいたときにはフラグを立ててデータを表示しないようにして、
スクロールが終わったときにフラグを外してデータを表示するようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// スクロールの状態を検知する
public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
 
    // スクロールしていない
    case OnScrollListener.SCROLL_STATE_IDLE:
 
        // スクロール中であることを示すフラグをfalseに
        mBusy = false;
 
        // ListViewの表示するべきデータ位置を取得
        int first = view.getFirstVisiblePosition();
        int count = view.getChildCount();
 
        // ListViewに表示するべきデータを設定する
        for (int i = 0; i < count; i++) {
            TextView t = (TextView) view.getChildAt(i);
            if (t.getTag() != null) {
                t.setText(mStrings[first + i]);
                t.setTag(null);
            }
        }
        break;
 
    // スクロール中
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        mBusy = true;
        break;
 
    // はじいたとき
    case OnScrollListener.SCROLL_STATE_FLING:
        mBusy = true;
        break;
    }
}

あとは、adapterのgetViewメソッドの実装を以下のようにします。
スクロール中であればデータを表示せずにLoadingと表示させます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public View getView(int position, View convertView, ViewGroup parent) {
    TextView text;
 
    if (convertView == null) {
        text = (TextView) mInflater.inflate(
                android.R.layout.simple_list_item_1, parent, false);
    } else {
        text = (TextView) convertView;
    }
 
    // スクロール中でなければデータを表示する
    if (!mBusy) {
        text.setText(mStrings[position]);
        text.setTag(null);
 
    // スクロール中であればデータを表示せずにLoadingと表示
    } else {
        text.setText("Loading...");
        // Non-null tag means the view still needs to load it's data
        text.setTag(this);
    }
 
    return text;
}