Qué tamaño almacenar imagen en el servidor para utilizar con la aplicación de Android
Tengo una aplicación de Android que permite al usuario subir fotos de perfil. Se almacenan 300px X 300px en el servidor.
En la aplicación, los uso en 40dp X 40dp o en ocasiones 100dp X 100dp. Las imágenes de 40dp están en ListView
. En realidad, utilizo un LazyList
terceros muy popular para almacenar las imágenes (usando una clase ImageLoader
) en un caché. Aquí está la biblioteca exacta .
- Tamaño del mapa de bits de Android Widget
- Cargando imágenes con Picasso desde el almacenamiento interno
- Android: lee la imagen PNG sin alpha y decodifica como ARGB_8888
- Cómo comprimir Bitmap como JPEG con la pérdida de calidad al menos en Android?
- Cómo combinar el mapa de bits de superposición y la imagen capturada en android?
Simplemente muestro la imagen en mi adapter
como este:
imageLoader.DisplayImage(profileUrl, holder.iv1);
Tomo la URL de la web y la muestro directamente en ImageView
40dp x 40dp.
A veces me doy cuenta de la degradación de la imagen. Donde la imagen se carga parcialmente, entonces está dañada.
Una teoría es que el ir de una imagen grande en el servidor y tratar de almacenarla en un área pequeña en la aplicación real, a continuación, hacer esto muchas veces en un ListView
, está causando algunos problemas de carga.
La pregunta: ¿Cuál es la mejor manera de manejar esta situación cuando tienes una imagen mucho más grande en el servidor de lo que necesitas mostrar? Estoy asumiendo que puede necesitar utilizar BitMapFactory
o una clase similar para construir una nueva imagen. Pero no estoy seguro. Siento que me falta un paso.
He aquí un ejemplo de una imagen en un ListView
que se ha corrompido, observe que esto no le sucede a todos. (Y sí que es Tobías de Arrested Development .)
Seguimiento : ¿Y cómo tomamos en consideración el tamaño de archivo para xxhdpi
, xhdpi
, etc, cuando la imagen viene del servidor y no la carpeta de recursos?
- Cómo corregir "lienzo: intentando utilizar un error de mapa de bits reciclado"?
- Escala de imagen sin perder calidad de imagen no funcionó
- Android: cómo crear un botón sobre Bitmap dinámicamente o botón OVERLAYING?
- Cómo convertir el formato de imagen NV21 en mapa de bits?
- PorterduffXfermode: borra una sección de un mapa de bits
- trabajar con imágenes grandes en android
- Obtener imagen uri de picasso?
- Android: el relleno dejó un mapa de bits con color blanco
La biblioteca que está utilizando parece que apenas se mantiene (la última actualización tiene al menos un año de antigüedad). Hay varias bibliotecas nuevas y probablemente mejores que resuelven el mismo problema. Mi favorito es Square's Picasso . Es muy sencillo de usar y soluciona muy bien la carga de imágenes dentro de un problema ListView.
Para responder más directamente a algunas de sus preguntas:
¿Cuál es la mejor manera de manejar esta situación cuando tienes una imagen mucho más grande en el servidor que necesitas mostrar?
Necesita subamplear el mapa de bits hasta el tamaño de destino. Google tiene una muy buena escribir sobre todo esto aquí .
Primero tienes que decodificar el bitmap estableciendo el booleano inJustDecodeBounds
para obtener el tamaño del mapa de bits.
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
A continuación, puede calcular el tamaño de la muestra en función de la altura y el ancho de su objetivo.
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
A continuación, puede utilizar el tamaño de muestra calculado para cargar el mapa de bits muestreado. El código final sería algo así como
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
¿Y cómo tomamos en consideración el tamaño de archivo para xxhdpi, xhdpi, etc, cuando la imagen viene del servidor y no la carpeta de recursos?
Puede calcular el tamaño de píxeles objetivo que desea reducir el tamaño de su mapa de bits mediante el siguiente fragmento:
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, "10", context.getResources().getDisplayMetrics());
TL, DR
Utilice el Picasso de Square y resolverá todos sus problemas.
Sugiero agregar un argumento a la URL que utilizas para solicitar la imagen (por ejemplo, &size=small
) y hacer que tu servidor mantenga varios tamaños de cada imagen. Algunos beneficios a esto son:
- Menor uso de datos de la aplicación
- Mejor calidad de imagen (no tener que volver a muestrear el iamge)
- Mejor rendimiento (los mapas de bits grandes tardan mucho más en cargarse)
Los inconvenientes son:
- Más complejidad (lógica para determinar qué tamaño solicitar)
- Más requisitos de almacenamiento en el servidor
Creo que los profesionales superan con creces los contras, y usted terminará con una experiencia de usuario mucho mejor.
Para su seguimiento, usted podría incluso tener argumentos para cada densidad (por ejemplo, &density=mdpi
) que serviría el tamaño apropiado (y podría simplemente cambiar getResources().getDisplayMetrics().densityDpi
para obtener el valor del argumento).
Por ejemplo:
int densityDpi = getResources().getDisplayMetrics().densityDpi; if (densityDpi <= DisplayMetrics.DENSITY_MEDIUM) { return "mdpi"; } else if (densityDpi <= DisplayMetrics.DENSITY_HIGH) { return "hdpi"; } else if (densityDpi <= DisplayMetrics.DENSITY_XHIGH) { return "xhdpi"; } else if (densityDpi <= DisplayMetrics.DENSITY_XXHIGH) { return "xxhdpi"; } else { return "xxxhdpi"; }
- Android: Google Analytics como parte del servicio de Google Play
- No se puede ejecutar dex: varios archivos dex definen Lcom / facebook / android / AsyncFacebookRunner $ 1;