2011年3月14日月曜日

Android ListViewで下までスクロールして次のリストを取得表示する

とりあえず作ったAndroidアプリでつまずいたり調べたりしたことのまとめ3。

とりあえず作ってみたAndroidアプリの中で一番苦労した部分。そして、きっともっと良い方法はあるであろうやり方。Threadの理解が足りていないのが原因だろう。イケてないやり方だが自分の振り返り用に一応メモしておく。

まず検索部分は初めてのAndroid 第3版の7章「世界との接続」の4節「Webサービスの使い方」の翻訳アプリを参考にして、guiThreadとsearchThreadを用意した。本を読めばわかるので、詳細は省く。
        guiThread = new Handler();
        searchThread = Executors.newSingleThreadExecutor();
で、下までいったら次のリストを検索とは下記のようにしてListenerをセットした。SearchTaskは初めてのAndroidでいうTranslateTaskにあたるもので、検索した結果のItemをItemListAdapterにaddしていくTask。今の商品リストにaddしたいので、今のItemListAdapterのilaをSearchTaskに渡している。
getListView().setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (totalItemCount == firstVisibleItem + visibleItemCount) { // ListView最下であるか

            if (offset == totalItemCount || totalItemCount % 20 != 0) { // 次のリストがあるか
                return;
            }
            offset = totalItemCount;
            String query = queryText.getText().toString().trim();
            if (query.length() == 0) {
                return;
            }
            try {
                SearchTask task = new SearchTask(MainActivity.this, Main.Activity.ila, query, offset);
                searchThread.submit(task);
            } catch (RejectedExecutionException e) {
            }
        }
    }

    public void onScrollStateChanged(AbsListView abslistview,int scrollState) {
    }
});
これを実行して下までスクロールして見ると、下記エラーで上手く動かない。いじれるのはcreateしたoriginal threadだけらしい。
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

ここから調べてみたり実行してみたりでトライアンドエラーの連続。結局上手い方法がわからなかった。

で、どうしたのかというと結局新しくnewして別のItemListAdapterをSearchTaskに渡すことにした。
getListView().setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (totalItemCount == firstVisibleItem + visibleItemCount) { // ListView最下であるか

            if (offset == totalItemCount || totalItemCount % 20 != 0) { // 次のリストがあるか
                return;
            }
            offset = totalItemCount;
            String query = queryText.getText().toString().trim();
            if (query.length() == 0) {
                return;
            }
            try {
                items = new ArrayList();
                for (int i = 0; i < MainActivity.this.ila.getCount(); i++) {
                   items.add(MainActivity.this.ila.getItem(i));
                }
                ItemListAdapter ila2 = new ItemListAdapter(MainActivity.this, items);
                SearchTask task = new SearchTask(MainActivity.this, ila2, query, offset);
                searchThread.submit(task);
            } catch (RejectedExecutionException e) {
            }
        }
    }

    public void onScrollStateChanged(AbsListView abslistview,int scrollState) {
    }
});
なんかイケてない気がする。あと、これだとリストの一番上に戻ってしまう。
getListView().setSelectionFromTop(offset, getListView().getHeight() - 30);
こんな感じにしておいた。-30は適当。しないと下にリストが追加されたのが分かりにくかったため^^;;

やっつけ実装感は否めない。もう少しThread周りを勉強して理解して出直してこよう。