java - ListView random IndexOutOfBoundsException en Froyo
android commonsware-cwac (2)
Después de mucho tiempo comprobando el código fuente de Android y no entendiendo este error, finalmente lo descifré.
El problema ocurre con los teléfonos Samsung, tienen una implementación diferente en la funcionalidad de sobre-desplazamiento y eso terminó lanzando esta excepción ya que trató de seleccionar un pie de página / encabezado fuera de límites (incluso cuando no hay vista de pie de página).
La solución que utilicé no es bonita, pero evitará que este error vuelva a suceder.
class MyFixedListView extends ListView {
@Override
protected void dispatchDraw(Canvas canvas) {
try {
super.dispatchDraw(canvas);
} catch (IndexOutOfBoundsException e) {
// samsung error
}
}
}
Ahora uso esta implementación de ListView
y el error se ha ido.
Realmente espero que esto ayude a cualquiera a usar adaptadores sin fin.
Tengo una aplicación con toneladas de descargas y estoy recibiendo mucho de este error:
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)
Como puede ver en el seguimiento de la pila, no hay una sola línea con mi código en él. Para reproducir esto, afortunadamente encontré un usuario con Froyo (2.2 p7) y acabo de desplazarme hacia abajo en una de las ListView
en el código. Después de un tiempo aleatorio, simplemente se congeló con esta excepción. Esto sucede cada vez en un momento diferente.
Es un ListView
con EndlessAdapter
detrás de él, solo agrega más y más filas. Aparentemente recibo este error cuando hago el "over-scroll" pero no puedo pensar en una forma de solucionarlo. Ya es bastante difícil de reproducir, pero con casi 200 usuarios en línea en todo momento, si continúan recibiendo este error, terminarán sin usar la aplicación.
Cualquier ayuda sería apreciada.
EDITAR: Ha habido un problema similar con otra persona con EndlessAdapter
. http://groups.google.com/group/cw-android/browse_thread/thread/4739ce05742841da/af59c779e99f5e23?lnk=gst&q=index#af59c779e99f5e23
Pero no es culpa de EndlessAdapter
. Es culpa de Android.
El mismo problema ocurre en mi aplicación cuando pruebo en las tabletas ICS. Sucede solo cuando tengo 11 elementos en la lista, cuando EndlessAdapter carga por 10 elementos al tiempo.
Este es un problema de condición de carrera. El problema proviene de la actualización del indicador keepOnAppending en el subproceso AsyncTask. Mientras ListView accede a GetCount en el subproceso de la interfaz de usuario ykeepOnAppending se establece en true, más adelante cuando llama a getView en el mismo subproceso de interfaz de usuario ykeepOnAppending ya se restablece en 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();
}
}
Como solución, cambié el código de AppendTask para que actualice keepOnAppending en el subproceso de UI, solo cuando se agregan nuevos elementos al adaptador.
Aquí está el código:
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();
}
}