QA@IT

ListViewを再描画するとIndexOutOfBoundsExceptionが起きる

5534 PV

ListViewのメニューから別Activityに遷移し、そこで選択された値をSharedPreferenceに設定しListViewに戻り、設定された値に基づいてListViewを再描画したいです。そこで、以下のように実装しました。

public class SampleActivity extends ListActivity {
    private ListView listView;
    private SampleListAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sample_list);

        listView = getListView();

        // サーバーから10件取得
        List<Items> items = ApiUtil.getItems();
        adapter = new SampleListAdapter(this, R.layout.sample_list, items);
        listView.setAdapter(adapter);

        listView.setOnScrollListener(new OnScrollListener() {
            // 下端までスクロールしたら次の10件を取得
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        adapter.notifyDataSetChanged();
    }
}

しかし、IndexOutOfBoundsExceptionが発生して強制終了することがあります。原因は、遷移前の表示位置に戻ろうとして、最初にロードされる10件を超えて参照してしまうためだと思って、以下のようにBundleの中身をクリアしたのですが、これでもうまくいきません。

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    savedInstanceState.clear();
}

文で説明するのが難しいのですが、どうすれば解決できるか分かる方がいればよろしくお願いします。


追記

例外は以下のとおりです。

E/AndroidRuntime(19664): java.lang.IndexOutOfBoundsException: Invalid index 23, size is 1
E/AndroidRuntime(19664):        at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
E/AndroidRuntime(19664):        at java.util.ArrayList.get(ArrayList.java:311)
E/AndroidRuntime(19664):        at android.widget.HeaderViewListAdapter.isEnabled(HeaderViewListAdapter.java:164)
E/AndroidRuntime(19664):        at android.widget.AbsListView.onTouchEvent(AbsListView.java:2310)
E/AndroidRuntime(19664):        at android.widget.ListView.onTouchEvent(ListView.java:3714)
E/AndroidRuntime(19664):        at android.view.View.dispatchTouchEvent(View.java:3938)
E/AndroidRuntime(19664):        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
E/AndroidRuntime(19664):        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
E/AndroidRuntime(19664):        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)E/AndroidRuntime(19664):        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
E/AndroidRuntime(19664):        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
E/AndroidRuntime(19664):        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1734)
E/AndroidRuntime(19664):        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1146)
E/AndroidRuntime(19664):        at android.app.Activity.dispatchTouchEvent(Activity.java:2102)
E/AndroidRuntime(19664):        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1718)
E/AndroidRuntime(19664):        at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2218)
E/AndroidRuntime(19664):        at android.view.ViewRoot.handleMessage(ViewRoot.java:1889)
E/AndroidRuntime(19664):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(19664):        at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(19664):        at android.app.ActivityThread.main(ActivityThread.java:3691)
E/AndroidRuntime(19664):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(19664):        at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(19664):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
E/AndroidRuntime(19664):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
E/AndroidRuntime(19664):        at dalvik.system.NativeStart.main(Native Method)

回答

例外の発生箇所/操作はどこなのでしょうか?
List画面に戻った時(onCreate)なのでしょうか?

例外の頭に、↓があり、「リストの23番目を要求されたが、リストサイズは1」と見えます。コメントに「サーバーから10件取得」とあり、その差異が気になります(コピペミスの可能性もありますが)。

E/AndroidRuntime(19664): java.lang.IndexOutOfBoundsException: Invalid index 23, size is 1

また、例外発生の契機は、おそらく、なんらかのタッチイベントかな?と思います。試してませんが、onCreateや、Listの再描画では、タッチイベントは発生しないと思うので、冒頭の質問となりました。

E/AndroidRuntime(19664): at android.widget.AbsListView.onTouchEvent(AbsListView.java:2310)

編集 履歴 (0)
  • 例外はListViewに戻ったときに発生します。

    別Activity(これもListVIewで設定を変更するもの)でタップすると、設定が変更されListViewに戻ります。戻ったあとに変更された設定に基づいてサーバーからデータを取得しなおしたいです。
    -

やはり難しいですね。。。

この辺が似たようなエラー内容なので参考にしてみてはいかがでしょうか。

http://stackoverflow.com/questions/8431342/listview-random-indexoutofboundsexception-on-froyo

http://stackoverflow.com/questions/3018809/another-arrayindexoutofboundsexception-in-listview

ActivityはListView→A→B→Cということでしたが、startActivityForResultですべて遷移していけば出来なくもないと思いますよ。(あまりキレイとは言えませんが)

あまり良いヒントにならずにすいませんm(_ _;)m

編集 履歴 (0)

詳しい状況が分からないので推測になります。

気になる点を

  • onResumeadapter.notifyDataSetChanged();をやっていますが、初回表示時はnullでエラーになると思います。(すいません、コレは勘違いです。)

  • onRestoreInstanceStateは関係ないと思われます。

  • 別Activityから戻った時に処理をするにはstartActivityForResultonActivityResultを使えばよいかと思います。この場合、onActivityResultSharedPreferenceの値を判定することになると思います。

何かしらのヒントになれば幸いです。

※せめてIndexOutOfBoundsException発生している箇所を教えて頂ければもっと状況が分かるかと思います。

編集 履歴 (1)
  • ご回答有難うございます。
    1点目ですが、onCreate内でadapterに代入しているのですが、それでもnullになるのでしょうか。手元では問題なく動いています。
    2点目ですが、例外の内容を追記しましたので、それを踏まえていただきたいです。
    -
  • 制限字数をオーバーしたので分けます。3点目ですが、説明不足だったのですが、設定を行うActivityはListView→A→B→Cと遷移したCなので、startActivityForResultは使えないのかなと思っています。 -
  • すいません、1点目は私の勘違いでした。例外の内容ありがとうございます。時間があるときに見てみます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。