¿Existe un reemplazo para el widget Galería con Reciclado de vistas?

El widget de Galería predeterminado en Android no recicla vistas: cada vez que se llama a la vista de una nueva posición, el widget siempre llama al método getView del adaptador con convertView establecido en null.

A medida que se desplaza hacia atrás y hacia adelante esto termina en un montón de vistas que se están creando, que el componente de reciclaje que la Galería los almacena en no parece reciclarlos lo suficientemente rápido para conducir a una situación de OOM.

Puede probar esto fácilmente con unas pocas imágenes de gran tamaño como sus elementos de galería, pero sólo un TextView lo hará al final. Coloque una sentencia de registro con un contador en el método getView de su adaptador también para ver cuántas nuevas vistas se crean.

¿Existe un widget de terceros que se comporta como una Galería pero que también implementa el reciclaje de vista?

Mi solución fue, al final, ir con la sugerencia de @ CommonsWare para modificar el código fuente de Gallery. También es necesario copiar los siguientes archivos:

  • AdapterView
  • AbsSpinner

Pero estos son bastante simples.

Después de que he modificado el código para hacer lo siguiente:

RecycleBin ( AbsSpinner )

  • Coloque los objetos en el reciclador uno tras otro, en lugar de según la posición
  • Recuperar objetos desde la parte inferior del reciclador, independientemente de la posición solicitada
  • La implementación existente suponía que cada posición diferente en el adaptador resultó en una vista única. Los cambios anteriores sólo son buenos si su Galería contiene sólo un tipo de elemento, si no, tendrá que agregar algún tipo de clave basada en el tipo de elemento y la cantidad de ese tipo requerida

Gallery

  • Reflexión utilizada (ugh) para modificar la variable mGroupFlags privada de ViewGroup para permitir que el niño vuelva a ordenar – También establezco un valor booleano que indica si el acceso al campo tuvo éxito y lo probé antes de usar el componente.
  • Se eliminaron todas las llamadas a mRecycler.clear()
  • El número de elementos que la galería tiene que mostrar cambia a medida que se desplaza y la implementación existente despejaría al reciclador cuando (a) setSelection fue llamado (b) se produjo un desplazamiento de movimiento

Con estas modificaciones mi contador en mi método newView en mi adaptador alcanzó … 7.

Aquí está el código (Puesto en el dominio público 2013/08/07 bajo http://en.wikipedia.org/wiki/WTFPL )

En realidad hay una alternativa, aunque no lo he probado personalmente:

https://github.com/falnatsheh/EcoGallery

Super tarde a la fiesta, pero he modificado EcoGallery para hacer algunas cosas más (y evitar algunos accidentes).

Lo he llamado TimelineGallery y es el mismo crap que la Galería , pero puede hacer scroll suave y no hace cosas extrañas cuando las imágenes se cargan asincrónicamente.

Para demostrarlo, la muestra utiliza Picasso y PullToRefresh.

El código original, los derechos de autor y tal pertenece a Google, así que culparlos por hacer un widget tan malo.

Nota final: No recomiendo el uso de la galería, es viejo, buggy, hacky y probablemente nunca se mantendrá. El problema no es arreglar sus bugs, el problema es que toda la arquitectura de la Galería está equivocada y como tal, arreglarla no es posible sin introducir más hacks.

Google se dio cuenta de esto y lo desaprobó. Utilice un ViewPager o un HorizontalScrollList y tratar con las limitaciones de cada uno.

Si todavía quieres seguir adelante y usar esta "galería", siéntete libre, funciona, pero puede bloquear tu aplicación y puede frustrarte.

Otro WorkAround más rápido para los problemas de OutOfMemory, es tratar de capturar el código en el que se decodifica la imagen y si se genera la excepción OutOfMemory, intenta decodificarla con resolución más pequeña de nuevo.

algo como esto:

 private static Bitmap decodeFile(File f, int size, int suggestedScale) { int scale = 1; Bitmap bmp = null; try { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f), null, o); // Find the correct scale value. It should be the power of 2. int width_tmp = o.outWidth, height_tmp = o.outHeight; if(suggestedScale > 0) scale = suggestedScale; else { if (width_tmp >= height_tmp) { scale = Math.round((float)(width_tmp) / size); } else { scale = Math.round((float)(height_tmp) / size); } } if(scale < 2) return BitmapFactory.decodeFile(f.getPath()); Debug.i(TAG, "width: " + width_tmp + " height: " + height_tmp + " scale: " + scale); // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) { } catch(OutOfMemoryError e) { Debug.i(TAG, "we retry it cause of an OutOfMemoryException"); return decodeFile(f, size, scale+1); } catch(Exception e){ Debug.w(TAG, e); } return bmp; } 

Por supuesto, ahora es posible, que verá diferentes resoluciones de la misma imagen en diferentes momentos – Pero al menos su Galería no se bloqueará más y siempre mostrará la mayor resolución que pueda.

  • Retener completamente WebView en fragmento tras rotación
  • Obtener ids de vista en un bucle for por programa?
  • Diseño de vistas personalizadas
  • Reemplazar fragmento dentro de un ViewPager
  • Listview expandible anidada en android
  • ¿Cómo obtener el lienzo actual?
  • ¿Dónde desasignar correctamente el mapa de bits en Android View?
  • Ampliación de la clase de Android View para agregar un dropshadow
  • Proper onDestroy () / Cómo evitar fugas de memoria
  • Animación giratoria androide
  • RemoveView no funciona después de LayoutInflater.inflate (resource, root, true)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.