Lo que quiero hacer : ejecutar un subproceso en segundo plano que calcule el contenido de ListView y actualice ListView parcialmente, mientras se calculan los resultados.
Lo que sé que debo evitar : no puedo meterme con el contenido de ListAdapter del subproceso en segundo plano, así que heredé AsyncTask y publiqué el resultado (agregue entradas al adaptador) de onProgressUpdate. Mi adaptador usa ArrayList de objetos de resultado, todas las operaciones en esas listas de matriz están sincronizadas.
La investigación de otras personas : no hay datos muy valiosos aquí . También sufrí bloqueos casi diarios para un grupo de ~ 500 usuarios, y cuando agregué el list.setVisibility(GONE)/trackList.setVisibility(VISIBLE)
bloqueo en onProgressUpdate, los bloqueos disminuyeron en un factor de 10 pero no desaparecieron. (se sugirió en respuesta )
Lo que recibí a veces : tenga en cuenta que ocurre muy raramente (una vez a la semana para uno de los 3.5k usuarios). Pero me gustaría deshacerme de este error por completo. Aquí hay un seguimiento parcial de la pila:
`java.lang.IllegalStateException:` The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296334, class android.widget.ListView) with Adapter(class com.transportoid.Tracks.TrackListAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1432)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2062)
at android.widget.ListView.onTouchEvent(ListView.java:3234)
at android.view.View.dispatchTouchEvent(View.java:3709)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:852)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
[...]
¿Ayuda? Ya no es necesario, ver abajo
RESPUESTA FINAL: Resultó que estaba llamando notifyDataSetChanged
cada 5 inserciones para evitar parpadeos y cambios repentinos en la lista. No se puede hacer de esa manera, siempre notifique al adaptador cuando cambie la lista base. Este error ya hace mucho que me desapareció.
Respuestas:
Tuve el mismo problema.
Estaba agregando elementos a mi
ArrayList
hilo externo de la interfaz de usuario.Solución: hice ambas cosas
adding the items
y llaménotifyDataSetChanged()
al hilo de la interfaz de usuario.fuente
Tuve el mismo problema, pero lo solucioné usando el método
de la clase
ListView
fuente
Este es un problema de subprocesos múltiples y el uso de bloques sincronizados correctamente Esto se puede evitar. Sin poner cosas adicionales en UI Thread y causar pérdida de capacidad de respuesta de la aplicación.
También me enfrenté a lo mismo. Y como la respuesta más aceptada sugiere que hacer cambios en los datos del adaptador desde UI Thread puede resolver el problema. Eso funcionará, pero es una solución rápida y fácil, pero no la mejor.
Como puede ver para un caso normal. La actualización del adaptador de datos desde el subproceso en segundo plano y la llamada a notifyDataSetChanged en el subproceso de IU funciona.
Esta excepción de estado ilegal surge cuando un subproceso de interfaz de usuario está actualizando la vista y otro subproceso de fondo cambia los datos nuevamente. Ese momento causa este problema.
Entonces, si sincronizará todo el código que está cambiando los datos del adaptador y haciendo una llamada a notifydatasetchange. Este problema debería desaparecer. Como se fue para mí y todavía estoy actualizando los datos del hilo de fondo.
Aquí está el código específico de mi caso para que otros lo consulten.
Mi cargador en la pantalla principal carga los contactos de la guía telefónica en mis fuentes de datos en segundo plano.
Este PhoneBookManager.getPhoneBookContacts lee el contacto de la agenda telefónica y los completa en los hashmaps. Que es directamente utilizable para los adaptadores de lista para dibujar la lista.
Hay un botón en mi pantalla. Eso abre una actividad donde se enumeran estos números de teléfono. Si configuro directamente Adaptador sobre la lista antes de que el hilo anterior termine su trabajo, el caso de navegación rápida ocurre con menos frecuencia. Aparece la excepción. Cuál es el título de esta pregunta SO. Entonces tengo que hacer algo como esto en la segunda actividad.
Mi cargador en la segunda actividad espera a que se complete el primer hilo. Hasta que muestre una barra de progreso. Verifique el loadInBackground de ambos cargadores.
Luego crea el adaptador y lo entrega a la actividad donde en el hilo ui llamo setAdapter.
Eso resolvió mi problema.
Este código es solo un fragmento. Debe cambiarlo para compilarlo bien.
Espero que esto ayude
fuente
Resolví esto por tener 2 listas. Una lista que uso solo para el adaptador, y hago todos los cambios / actualizaciones de datos en la otra lista. Esto me permite hacer actualizaciones en una lista en un subproceso en segundo plano y luego actualizar la lista "adaptador" en el subproceso principal / UI:
fuente
Escribí este código y lo ejecuté en una imagen del emulador 2.1 durante ~ 12 horas y no obtuve la IllegalStateException. Voy a darle al marco de Android el beneficio de la duda sobre este y diré que es muy probable que sea un error en su código. Espero que esto ayude. Tal vez pueda adaptarlo a su lista y datos.
fuente
Hace varios días me encontré con el mismo problema y provoca varios miles de bloqueos por día, aproximadamente el 0.1% de los usuarios se encuentran con esta situación. Lo intenté
setVisibility(GONE/VISIBLE)
yrequestLayout()
, pero el conteo de accidentes solo disminuye un poco.Y finalmente lo resolví. Nada con
setVisibility(GONE/VISIBLE)
. Nada conrequestLayout()
.Finalmente descubrí que la razón es que usé una
Handler
llamadanotifyDataSetChanged()
después de actualizar los datos, lo que puede conducir a una especie de:checkForTap()
/onTouchEvent()
y finalmente llamalayoutChildren()
)notifyDataSetChanged()
y actualiza las vistasY cometí otro error que
getCount()
,getItem()
ygetView()
, uso directamente los campos en DataSource, en lugar de copiarlos en el adaptador. Entonces finalmente se bloquea cuando:getCount()
ygetView()
se llama, y listview encuentra que los datos no son consistentes y genera excepciones comojava.lang.IllegalStateException: The content of the adapter has changed but...
. Otra excepción común esIndexOutOfBoundException
si usa encabezado / pie de páginaListView
.Entonces, la solución es fácil, solo copie datos al adaptador desde mi DataSource cuando mi controlador activa el adaptador para obtener datos y llamadas
notifyDataSetChanged()
. El choque ahora nunca vuelve a suceder.fuente
Si esto sucediera de forma intermitente, resulta que solo tuve este problema cuando la lista se desplazó después de hacer clic en un último elemento de "cargar más". Si la lista no se desplazaba, todo funcionaba bien.
Después de MUCHA depuración, fue un error de mi parte, pero también una inconsistencia en el código de Android.
Cuando ocurre la validación, este código se ejecuta en ListView
Pero cuando ocurre onChange, activa este código en AdapterView (padre de ListView)
¡Observe la forma en que NO se garantiza que el adaptador sea el mismo!
En mi caso, dado que era un 'LoadMoreAdapter', estaba devolviendo el WrappedAdapter en la llamada getAdapter (para acceder a los objetos subyacentes). Esto dio como resultado que los recuentos fueran diferentes debido al elemento adicional 'Cargar más' y a que se lanzara la Excepción.
Solo hice esto porque los documentos hacen que parezca que está bien hacerlo
ListView.getAdapter javadoc
fuente
Mi problema estaba relacionado con el uso de un filtro junto con ListView.
Al configurar o actualizar el modelo de datos subyacente de ListView, estaba haciendo algo como esto:
Llamar
filter()
en la última línea hará (y debe) hacernotifyDataSetChanged()
que se llame en elpublishResults()
método del Filtro . Esto puede funcionar bien a veces, especialmente en mi rápido Nexus 5. Pero en realidad, está ocultando un error que notará con dispositivos más lentos o en condiciones de uso intensivo de recursos.El problema es que el filtrado se realiza de forma asincrónica y, por lo tanto, entre el final de la
filter()
declaración y la llamada apublishResults()
, tanto en el subproceso de la interfaz de usuario, se puede ejecutar algún otro código de subproceso de la interfaz de usuario y cambiar el contenido del adaptador.La solución real es fácil, solo llame
notifyDataSetChanged()
antes de solicitar que se realice el filtrado:fuente
Tengo una lista de objetos de alimentación. Se adjunta y se trunca desde el subproceso sin interfaz de usuario. Funciona bien con el adaptador a continuación. Llamo
FeedAdapter.notifyDataSetChanged
al hilo de la interfaz de usuario de todos modos, pero un poco más tarde. Me gusta esto porque mis objetos Feed permanecen en la memoria en el Servicio local incluso cuando la IU está muerta.fuente
Estaba enfrentando el mismo problema con exactamente el mismo registro de errores. En mi caso
onProgress()
de AsyncTask agrega los valores al adaptador usandomAdapter.add(newEntry)
. Para evitar que la interfaz de usuario se vuelva menos receptiva, configuromAdapter.setNotifyOnChange(false)
y llamomAdapter.notifyDataSetChanged()
4 veces por segundo. Una vez por segundo, se ordena la matriz.Esto funciona bien y se ve muy adictivo, pero desafortunadamente es posible bloquearlo tocando los elementos de la lista que se muestran con la frecuencia suficiente.
Pero parece que he encontrado una solución aceptable. Supongo que incluso si solo trabajas en el subproceso de interfaz de usuario, el adaptador no acepta muchos cambios en sus datos sin llamar
notifyDataSetChanged()
, debido a esto creé una cola que almacena todos los elementos nuevos hasta que terminen los 300 ms mencionados. Si se llega a este momento, agrego todos los elementos almacenados de una sola vez y llamonotifyDataSetChanged()
. Hasta ahora ya no podía bloquear la lista .fuente
Este es un error conocido en Android 4 a 4.4 (KitKat) y se resuelve en "> 4.4"
Ver aquí: https://code.google.com/p/android/issues/detail?id=71936
fuente
Incluso cuando enfrenté el mismo problema en mi aplicación de notificación XMPP, el mensaje de los receptores debe agregarse nuevamente a la vista de lista (implementado con
ArrayList
). Cuando intenté agregar el contenido del receptor a través deMessageListener
(hilo separado), la aplicación se cierra con el error anterior. Lo resolví agregando el contenido a mi métodoarraylist
&setListviewadapater
throughrunOnUiThread
, que es parte de la clase Activity. Esto resolvió mi problema.fuente
Me enfrenté a un problema similar, así es como lo resolví en mi caso. Verifico si
task
ya estáRUNNING
oFINISHED
porque una tarea puede ejecutarse solo una vez. A continuación verá un código parcial y adaptado de mi solución.fuente
Tuve el mismo problema y lo resolví. Mi problema era que estaba usando un
listview
, con un adaptador de matriz y con filtro. En el métodoperformFiltering
estaba jugando con la matriz que tiene los datos y fue el problema ya que este método no se ejecuta en el hilo de la interfaz de usuario y EVENTUALMENTE plantea algunos problemas.fuente
Una de las causas de este bloqueo es que el
ArrayList
objeto no puede cambiar por completo. Entonces, cuando elimino un elemento, tengo que hacer esto:Esto solucionó el bloqueo para mí.
fuente
En mi caso, llamé al método
GetFilter()
en un adaptador desde elTextWatcher()
método de la actividad principal, y agregué los datos con un bucle For activadoGetFilter()
. La solución fue cambiar el bucle For porAfterTextChanged()
el método secundario en la actividad principal y eliminar la llamada aGetFilter()
fuente
fuente
También recibía exactamente el mismo error y usaba AsyncTask:
Lo resolví poniendo
adapter.notifyDataSetChanged();
en la parte inferior de mi hilo de interfaz de usuario, ese es mi método AsyncTask onPostExecute. Me gusta esto :Ahora mi aplicación funciona.
EDITAR: De hecho, mi aplicación todavía se bloqueaba cada 1 de cada 10 veces, dando el mismo error.
Finalmente me encontré
runOnUiThread
con una publicación anterior, que pensé que podría ser útil. Así que lo puse en mi método doInBackground, así:Y eliminé el
adapter.notifyDataSetChanged();
método. Ahora, mi aplicación nunca se bloquea.fuente
Pruebe una de estas soluciones:
A veces, si agrega un nuevo objeto a la lista de datos en un hilo (o
doInBackground
método), se producirá este error. La solución es: crear una lista temporal y agregar datos a esta lista en el subproceso (odoInBackground
), luego copiar todos los datos de la lista temporal a la lista de adaptadores en el subproceso de la interfaz de usuario (oonPostExcute
)Asegúrese de que todas las actualizaciones de la IU se invoquen en el subproceso de la IU.
fuente
Tuve el mismo problema al agregar nuevos datos en el cargador de imágenes perezoso que acabo de poner
en
espero que te ayude
fuente
Como @Mullins dijo "Agregué
los elementos y llamé
notifyDataSetChanged()
al hilo de la interfaz de usuario y resolví esto. - Mullins".En mi caso tengo
asynctask
y llaménotifyDataSetChanged()
aldoInBackground()
método y el problema está resuelto, cuando llamé desdeonPostExecute()
recibí la excepción.fuente
Tenía una costumbre
ListAdapter
y estaba llamandosuper.notifyDataSetChanged()
al principio y no al final del métodofuente
Tenía la misma situación, tenía muchos grupos de buttong dentro de mi elemento en la vista de lista y estaba cambiando algunos valores booleanos dentro de mi elemento como holder.rbVar.setOnclik ...
mi problema ocurrió porque estaba llamando a un método dentro de getView (); y estaba guardando un objeto dentro de sharepreference, así que tuve el mismo error arriba
Cómo lo resolví; Eliminé mi método dentro de getView () para notifyDataSetInvalidated () y el problema desapareció
fuente
Yo tuve el mismo problema. finalmente obtuve la solución
antes de actualizar la vista de lista, si el teclado virtual está presente, ciérrelo primero. después de eso establezca la fuente de datos y llame a notifydatasetchanged ()
mientras se cierra el teclado internamente listview actualizará su interfaz de usuario. sigue llamando hasta cerrar el teclado. esa vez, si el origen de datos cambia, arrojará esta excepción. Si los datos se actualizan en onActivityResult, existe la posibilidad de que ocurra el mismo error.
fuente
Mi solución:
1) crear un
temp ArrayList
.2) realiza tus trabajos pesados (búsqueda de fila sqlite, ...) en
doInBackground
método y agregue elementos a la lista temporal de matrices.3) agregue todos los elementos de temp araylist a su lista de arraylist en el
onPostExecute
método.note:
es posible que desee eliminar algunos elementos de la vista de lista y también eliminar de la base de datos sqlite y tal vez eliminar algunos archivos relacionados con los elementos de sdcard, simplemente elimine los elementos de la base de datos y elimine sus archivos relacionados y agréguelos a la lista temporal de matricesbackground thread
. entonces enUI thread
elimine los elementos existentes en la lista temporal de la lista de la lista.Espero que esto ayude.
fuente