Подтвердить что ты не робот

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. Это андроидная неисправность.

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Это проблема гонки. Проблема связана с обновлением флага keepOnAppending в потоке AsyncTask. В то время как ListView обращается к getCount в потоке пользовательского интерфейса andkeepOnAppending имеет значение true, позже, когда он вызывает getView в одном и том же потоке пользовательского интерфейса, andkeepOnAppending уже reset в 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();
    }
}