いろいろガンガンいこうぜ。体も大事に

普段はJavaでAndroidアプリ開発しているプログラマーのブログです。

ListViewが一番下までスクロールした時点で追加要素を読み込むようにしたら,スクロールしていないのに要素が1回追加されていた

結論から言うと原因は,AbsListView.OnScrollListenerのonScrollメソッドの仕様を勘違いしていて,このメソッドがスクロールしていなくても呼ばれていたためのようです。


Twitterクライアントのようなものを想定しています。
ListViewが一番下までスクロールした時点で追加要素を取得し,読み込み,リストビューに加えようとしていました。

こちらのブログを参考に,実装させていただきました。
http://visible-true.blogspot.jp/2010/12/listview.html



さて,

ActivityのonCreateメソッド内で次のように書いていました。

listView.addFooterView(LayoutInflater.from(footerViwe);
listView.setOnScrollListener(new OnScrollListener() {
	@Override
	public void onScroll(
		AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
			boolean isLastItemVisible = totalItemCount == firstVisibleItem + visibleItemCount;
			if (isLastItemVisible && !isLoading()) {
				loadNewItems();
			}
		}
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
	}
});
setListAdapter(adapter);

loadNewItems();

footerViewにはプログレスバーなどが含まれています。loadItemsメソッド内で,追加要素をロードして,adapterのnotifyDatasetChangedメソッドを読んでいます。isLoading()メソッドは,名前通り追加要素を読み込み中かどうか判断します。onScrollメソッドが複数回呼ばれるため,複数回ロードされるのを防ぐための処理です。



このように,フッターでリストの末尾に常にプログレスバーを表示して,末尾までスクロールしたら追加要素のロードを開始するようにしていました。



さてこのようなコードで初期状態を20個,スクロールするごとに要素を20個追加しようとしました。リストの最後までスクロールするごとに,正しく20個要素が追加されます。


しかし,なぜ初期状態要素が40個になっていました。


どうやらloadNewItemsメソッドがスクロールしていなくても2回呼ばれいるようです。
調べてみると,

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 

が,スクロールしていないのに複数回呼ばれていました。
そのうちの最初の1回は引数のfirstVisibleItem, visibleItemCount, totalItemCountは全て0になっており,そのタイミングでloadItemsメソッドが呼ばれてしまっていました。

そのため,onCreate内で1回目とOnScrollListenerのonScroll内で2回目,計2回loadItemsがよばれて初期の状態が40個の要素が入ってしまっていたようです。


また,どうやらユーザーが画面をスクロールしていなくても,ListViewに要素が追加されたタイミングでもonScrollが呼ばれているようです。




このように,onScrollメソッドの呼ばれるタイミングの仕様を勘違いしていたことが原因のようです。onCreateの中のloadItemsメソッドの呼び出しを消して解消しました。