ListView en orden ArrayAdapter get mezclado cuando se desplaza

Tengo un ListView en un ArrayAdapter personalizado que muestra un ícono ImageView y un TextView en cada fila. Cuando hago la lista el tiempo suficiente para permitirle desplazarme, el orden comienza correctamente, pero cuando empiezo a desplazarme hacia abajo, algunas de las entradas anteriores comienzan a reaparecer. Si me desplazo hacia atrás, el orden anterior cambia. Hacer esto repetidamente eventualmente hace que todo el orden de la lista sea aparentemente aleatorio. Por lo tanto, si se desplaza por la lista, el orden secundario cambia o el dibujo no se actualiza correctamente.

¿Qué podría causar que algo como esto suceda? Necesito que el orden en que se muestran los elementos para el usuario sea del mismo orden en que se agregaron a ArrayList, o al MENOS que permanezcan en un orden estático. Si necesito proporcionar información más detallada, házmelo saber. Cualquier ayuda es apreciada. Gracias.

Tenía problemas similares, pero al hacer clic en un elemento de la lista personalizada, los elementos de la pantalla se invertían en secuencia. Si volviera a hacer clic, retrocederían a donde estaban originalmente.

Después de leer esto, verifiqué mi código donde sobrecargo el método getView. Estaba obteniendo la vista desde la vista convertida, y si era nula, ahí es cuando construía mis cosas. Sin embargo, después de colocar un punto de interrupción, descubrí que llamaba a este método en cada clic y en los clics posteriores, convertView no era nulo, por lo tanto, los elementos no se estaban configurando.

Aquí hay un ejemplo de lo que era:

public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = vi.inflate(R.layout.listitemrow, null); RssItem rssItem = (RssItem) super.getItem(position); if (rssItem != null) { TextView title = (TextView) view.findViewById(R.id.rowtitle); if (title != null) { title.setText(rssItem.getTitle()); } } } return view; } 

El cambio sutil está moviendo el corsé cercano para la verificación nula en la vista justo después de inflar:

 public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = vi.inflate(R.layout.listitemrow, null); } RssItem rssItem = (RssItem) super.getItem(position); if (rssItem != null) { TextView title = (TextView) view.findViewById(R.id.rowtitle); if (title != null) { title.setText(rssItem.getTitle()); } } return view; } 

Espero que esto ayude a otros que experimenten este mismo problema.

Para aclarar aún más la respuesta de farcats a continuación de manera más general, aquí está mi explicación:

La operación vi.inflate (necesaria aquí para analizar el diseño de una fila desde XML y crear el objeto View apropiado) está envuelta por una statement if (ver == nulo) para la eficiencia, por lo que el inflado del mismo objeto no ocurrirá una y otra vez cada vez que aparece a la vista.

SIN EMBARGO, las otras partes del método getView se usan para establecer otros parámetros y, por lo tanto, NO deberían incluirse dentro de la statement if (view == null) .

De manera similar, en otra implementación común de este método, algunos elementos textView, ImageView o ImageButton deben ser poblados por valores de la lista [posición], usando findViewById y después de eso operaciones .setText o .setImageBitmap . Estas operaciones deben venir después de crear una vista desde cero por inflación y obtener una vista existente si no es nula.

Otro buen ejemplo en el que se aplica esta solución para BaseAdapter aparece en BaseAdapter, lo que hace que ListView se descomponga cuando se desplaza

El ListView reutiliza objetos de vista cuando se desplaza. ¿Estás anulando el método getView? Debe asegurarse de configurar cada propiedad para cada vista, no suponga que recordará lo que tenía antes. Si publica ese método, es probable que alguien lo señale en la parte incorrecta.

Tengo un ListView, AdapterView y una vista (search_options) que contiene EditText y 3 Spinners. Los elementos ListView son varias copias de la distribución (search_options), donde el usuario puede agregar más opciones en ListView y luego hacer clic en buscar para enviar la consulta sql creada de acuerdo con las opciones de los usuarios.

Encontré que las indefiniciones de mezcla convertView así que agregué una lista global (myViews) en actividad y la pasé a ArrayAdapter. Luego, en ArrayAdapter (getView) agrego cada vista recién agregada a él (myViews).

También en getView en lugar de verificar si convertView es nulo, verifico si la lista global (myViews) tiene una vista sobre la posición (seleccionada) seleccionada. ¡¡Solucionó problemas por completo después de perder 3 días leyendo Internet !!

1- en Actividad agrega esto:

 Map myViews = new HashMap<>(); 

y luego pasarlo a ArrayAdapter usando el constructor del adaptador.

 mSOAdapter = new SearchOptionsAdapter(getActivity(), resultStrs, myViews); 

2- en getView:

 @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder viewHolder; if (!myViews.containsKey(position)) { viewHolder = new ViewHolder(); LayoutInflater inflater = LayoutInflater.from(getContext()); view = inflater.inflate(R.layout.search_options, parent, false); /// ...... YOUR CODE myViews.put(position, view); FontUtils.setCustomFontsIn(view, getContext().getAssets()); }else { view = myViews.get(position); } return view; } 

Finalmente no más elementos de mezcla …