ListView random IndexOutOfBoundsException на Froyo

У меня есть приложение с множеством загрузок, и я получаю много этой ошибки:

16783 AndroidRuntime E java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0 16783 AndroidRuntime E at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257) 16783 AndroidRuntime E at java.util.ArrayList.get(ArrayList.java:311) 16783 AndroidRuntime E at android.widget.HeaderViewListAdapter.isEnabled(HeaderViewListAdapter.java:16 4) 16783 AndroidRuntime E at android.widget.ListView.dispatchDrawWithExcessScroll_Default(ListView.java:3 288) 16783 AndroidRuntime E at android.widget.ListView.dispatchDraw(ListView.java:3029) 16783 AndroidRuntime E at android.view.View.draw(View.java:6743) 16783 AndroidRuntime E at android.widget.AbsListView.draw(AbsListView.java:2549) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1640) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.View.draw(View.java:6743) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1640) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.View.draw(View.java:6743) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1640) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.ViewGroup.drawChild(ViewGroup.java:1638) 16783 AndroidRuntime E at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) 16783 AndroidRuntime E at android.view.View.draw(View.java:6743) 16783 AndroidRuntime E at android.widget.FrameLayout.draw(FrameLayout.java:352) 16783 AndroidRuntime E at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java :1885) 16783 AndroidRuntime E at android.view.ViewRoot.draw(ViewRoot.java:1407) 16783 AndroidRuntime E at android.view.ViewRoot.performTraversals(ViewRoot.java:1163) 16783 AndroidRuntime E at android.view.ViewRoot.handleMessage(ViewRoot.java:1727) 16783 AndroidRuntime E at android.os.Handler.dispatchMessage(Handler.java:99) 16783 AndroidRuntime E at android.os.Looper.loop(Looper.java:123) 16783 AndroidRuntime E at android.app.ActivityThread.main(ActivityThread.java:4627) 16783 AndroidRuntime E at java.lang.reflect.Method.invokeNative(Native Method) 16783 AndroidRuntime E at java.lang.reflect.Method.invoke(Method.java:521) 16783 AndroidRuntime E at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:8 58) 16783 AndroidRuntime E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 16783 AndroidRuntime E at dalvik.system.NativeStart.main(Native Method) 

Как вы можете видеть в трассировке стека, в моей кодовой трассе нет одной строки. Чтобы воспроизвести это, я, к счастью, нашел пользователя с Froyo (2.2 p7), и я просто прокрутил один из ListView в коде. После некоторого случайного времени он просто застыл с этим исключением. Это происходит каждый раз в другое время.

Это ListView с EndlessAdapter за ним, просто добавляя все больше и больше строк. По-видимому, я получаю эту ошибку, когда выполняю «сверхпрокрутку», но я даже не могу придумать, как это исправить. Достаточно сложно воспроизвести, но с почти 200 пользователями онлайн каждый раз, если они продолжают получать эту ошибку, они больше не будут использовать приложение.

Любая помощь будет оценена по достоинству.

EDIT: Аналогичная проблема была с кем-то еще с EndlessAdapter . http://groups.google.com/group/cw-android/browse_thread/thread/4739ce05742841da/af59c779e99f5e23?lnk=gst&q=index#af59c779e99f5e23

Но это не EndlessAdapter . Это ошибка андроида.

После много времени проверяя исходный код Android и не понимая эту ошибку, я, наконец, взломал ее.

Проблема возникает с телефонами Samsung, у них есть другая реализация над функциями прокрутки, и это закончилось тем, что выбрасывало это исключение, поскольку оно пыталось выбрать нижний колонтитул / градиент вне пределов (даже если нет нижнего колонтитула).

Решение, которое я использовал, не очень красивое, но оно перестанет повторяться.

 class MyFixedListView extends ListView { @Override protected void dispatchDraw(Canvas canvas) { try { super.dispatchDraw(canvas); } catch (IndexOutOfBoundsException e) { // samsung error } } } 

Теперь я использую эту реализацию ListView и ошибка исчезла.

Я действительно надеюсь, что это поможет любому, кто использует бесконечные адаптеры.

Такая же проблема возникает в моем приложении при тестировании на ICS-планшетах. Это происходит только тогда, когда у меня есть 11 элементов в списке, когда EndlessAdapter загружается на 10 элементов по времени.

Это проблема гонки. Проблема связана с обновлением флага keepOnAppending в потоке AsyncTask. В то время как ListView обращается к getCount в потоке пользовательского интерфейса andkeepOnAppending имеет значение true, позже, когда он вызывает getView в одном и том же потоке пользовательского интерфейса, andkeepOnAppending уже сбрасывается в doInBackground:

 @Override public int getCount() { if (keepOnAppending.get()) { return (super.getCount() + 1); // one more for // "pending" } return (super.getCount()); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (position == super.getCount() && keepOnAppending.get()) { if (pendingView == null) { pendingView = getPendingView(parent); executeAsyncTask(new AppendTask()); } return (pendingView); } return (super.getView(position, convertView, parent)); } class AppendTask extends AsyncTask<Void, Void, Exception> { @Override protected Exception doInBackground(Void... params) { Exception result = null; try { keepOnAppending.set(cacheInBackground()); } catch (Exception e) { result = e; } return (result); } @Override protected void onPostExecute(Exception e) { if (e == null) { appendCachedData(); } else { keepOnAppending.set(onException(pendingView, e)); } pendingView = null; notifyDataSetChanged(); } } 

В качестве исправления я изменил код AppendTask так, чтобы он обновлял keepOnAppending в потоке пользовательского интерфейса, только когда новые элементы добавлены в адаптер.

Вот код:

 class AppendTask extends AsyncTask<Void, Void, AppendTask.Result> { class Result { boolean status; Exception ex; public Result(Exception ex) { this.ex = ex; } public Result(boolean result) { this.status = result; } } @Override protected AppendTask.Result doInBackground(Void... params) { try { return new Result(cacheInBackground()); } catch (Exception e) { return new Result(e); } } @Override protected void onPostExecute(AppendTask.Result result) { if (result.ex == null) { appendCachedData(); keepOnAppending.set(result.status); } else { keepOnAppending.set(onException(pendingView, result.ex)); } pendingView = null; notifyDataSetChanged(); } }