example - libreria glide android
AsignaciĆ³n de mapa de bits, utilizando BitmapFactory.Options.inBitmap lanza IllegalArgumentException (6)
¿Por qué estás decodificando mapas de bits? Solo haz:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setImageResource(R.drawable.img1);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageView.setImageResource(R.drawable.img2);
}
});
}
¿Estás seguro de que ambas imágenes tienen la misma dimensión? Segun docs
Si [inBitmap está] establecido, los métodos de decodificación que toman el objeto Opciones intentarán reutilizar este mapa de bits al cargar contenido. Si la operación de decodificación no puede usar este mapa de bits, el método de decodificación devolverá un valor nulo y lanzará una IllegalArgumentException. La implementación actual requiere que el mapa de bits reutilizado sea mutable, y el mapa de bits reutilizado resultante seguirá siendo mutable incluso cuando se decodifica un recurso que normalmente resultaría en un mapa de bits inmutable.
Aún así, siempre debe utilizar el Mapa de bits devuelto del método de decodificación y no asumir que la reutilización del mapa de bits funcionó, debido a las restricciones descritas anteriormente y las situaciones de falla que pueden ocurrir. La verificación de si el valor de retorno coincide con el valor del conjunto inBitmap en la estructura de Opciones indicará si el mapa de bits se reutilizó, pero en todos los casos debe usar el Mapa de bits devuelto por la función de decodificación para asegurarse de que está utilizando el mapa de bits que se usó como El destino de decodificación.
Uso con BitmapFactory
A partir de KITKAT, BitmapFactory puede reutilizar cualquier mapa de bits mutable para decodificar cualquier otro mapa de bits siempre que el recuento de bytes del mapa de bits descodificado sea menor o igual que el recuento de bytes asignado del mapa de bits reutilizado. Esto puede deberse a que el tamaño intrínseco es más pequeño, o su escala de tamaño posterior (para densidad / tamaño de muestra) es menor.
Antes de KITKAT se aplican restricciones adicionales: la imagen que se está decodificando (ya sea como un recurso o como un flujo) debe estar en formato jpeg o png. Solo se admiten mapas de bits de igual tamaño, con inSampleSize establecido en 1. Además, la configuración del mapa de bits reutilizado anulará la configuración de inPreferredConfig, si se establece.
EDITAR:
Si tiene un mapa de bits de recursos grande, simplemente cárguelo en asynctask ... Más información HERE pero se puede hacer mucho más simple.
Obtengo la siguiente excepción: Problema de decodificación en el mapa de bits existente , al configurar inBitmap
en verdadero;
Causado por: java.lang.IllegalArgumentException: Problema de decodificación en el mapa de bits existente
en android.graphics.BitmapFactory.decodeResource (BitmapFactory.java:460)
...
Lo interesante es que el mismo código falla en diferentes lugares cuando se ejecuta en:
- API: 4.4.2, Nexus 4
- API: 4.3.1, Samsung s3
Este es mi código, que es una copia como se muestra en este video DevBytes: Bitmap Allocation .
private BitmapFactory.Options options;
private Bitmap reusedBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = (ImageView) findViewById(R.id.image_view);
// set the size to option, the images we will load by using this option
options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inMutable = true;
BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);
// we will create empty bitmap by using the option
reusedBitmap = Bitmap.createBitmap(options.outWidth, options.outHeight, Bitmap.Config.ARGB_8888);
// set the option to allocate memory for the bitmap
options.inJustDecodeBounds = false;
options.inSampleSize = 1;
options.inBitmap = reusedBitmap;
// #1
reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);
imageView.setImageBitmap(reusedBitmap);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
options.inBitmap = reusedBitmap;
// #2
reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2, options);
imageView.setImageBitmap(reusedBitmap);
}
});
}
- Nexus 4, se bloquea en
BitmapFactory.decodeResource()
en// #1
- S3, pasa el # 1 y muestra la primera imagen, pero luego se bloquea al hacer clic en la imagen en
BitmapFactory.decodeResource()
en// #2
Algunas notas:
- Las imágenes están en el mismo tamaño. Intenté
jpg
ypng
. Falla en ambos. - Los mapas de bits son mutables.
- Lo comprobé utilizando este método
canUseForInBitmap
, como se describe aquí .
Pregunta:
¿Cómo usar esta propiedad inBitmap
correctamente?
Si encontraste tal problema o ves que hice algo estúpido, por favor comenta / responde. Cualquier ayuda, será apreciada. Si conoces alguna solución, será genial.
- Editar (la pregunta sigue abierta) -
Lo siento por no explicar la razón por la que estoy tratando de reutilizar los mapas de bits de esa manera.
La razón de esto es GC que se bloquea cada vez que decide liberar la memoria.
inBitmap
función inBitmap
debería ayudarnos a reutilizar el mapa de bits sin asignar una nueva memoria, lo que hará que GC limpie la memoria ya asignada.
Por ejemplo, si uso este enfoque común:
Log.i("my_tag", "image 1");
imageView.setImageResource(R.drawable.img1);
Log.i("my_tag", "image 2");
imageView.setImageResource(R.drawable.img2);
Log.i("my_tag", "image 3");
imageView.setImageResource(R.drawable.img3);
Entonces este será el trabajo de GC :
I/my_tag ( 5886): image 1
D/dalvikvm( 5886): GC_FOR_ALLOC freed 91K, 2% free 9113K/9240K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.914MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20362K/20492K, paused 13ms, total 13ms
I/my_tag ( 5886): image 2
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11252K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.912MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 35ms, total 35ms
I/my_tag ( 5886): image 3
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11250K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.913MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 32ms, total 32ms
¡Esto es más de 100 ms de hilo principal bloqueado!
Lo mismo sucederá si decodeResource()
sin la opción inBitmap
. Así que la pregunta sigue abierta, ¿cómo usar esta propiedad?
Deberá establecer options.inMutable en true antes de # 1 y # 2 en su código. Esto puede sonar un poco más, pero estas son pequeñas minas que has pisado.
Espero que esto ayude
Es un poco extraño que cree un nuevo mapa de bits y luego intente reutilizarlo. ¿Por qué no dejar que decodeResource
cree un nuevo mapa de bits en primer lugar? Sospecho que su problema en el # 2 es que una vez que haya configurado ImageView
para usar el mapa de bits, no podrá volver a utilizarlo (porque ya está en uso). La IllegalArgumentException
se menciona en los docs :
Si la operación de decodificación no puede usar este mapa de bits, el método de decodificación devolverá un valor nulo y lanzará una IllegalArgumentException.
En cuanto a una solución alternativa, puede intentar mantener dos mapas de bits y cambiar a cuál de ellos está apuntando el ImageView
, por ejemplo:
- decodificar a mapa de bits 1, punto
ImageView
a mapa de bits 1 - decodificar a mapa de bits 2, punto
ImageView
a mapa de bits 2 - repita desde el paso 1
No estoy seguro del problema que encontraste con Samsung S3 en el # 2. Pero el problema con el que se encontró con Nexus 4 puede deberse a que colocó dos imágenes en una carpeta mal dibujada de dpi. Entonces, cuando intenta descodificar el mapa de bits, no puede encontrar los recursos.
Mi teléfono tiene densidad de pantalla es hdpi, al principio trato de poner dos imágenes en drawable-mdpi, y enfrento el problema con el # 1. Así que lo cambié a drawable-hdpi, y funcionó.
Probé tu código con Nexus 4 emulado.
Tenía el archivo ic_launcher.png predeterminado, que copié y pegué dos veces en drawable-mdpi (como normalmente lo hago). Cambié el nombre de los dos nuevos archivos para que coincidan con los nombres en su código (para que tenga menos cambios que hacer allí).
Cuando ejecuto la aplicación observé lo mismo que tú.
Después de varios intentos diferentes, decidí copiar los nuevos paquetes a otras carpetas dibujables, para que estuvieran presentes en:
- dibujable-hdpi
- dibujable-mdpi
- drawable-xhdpi
- drawable-xxhdpi
¡Ejecuto la aplicación y está funcionando!
No estoy realmente seguro de por qué funciona, pero obviamente tiene que ser algo con la resolución / densidad de pantalla correcta.
Simplemente ponga largeHeap = "true" en la etiqueta de la aplicación (AndroidManifest.xml)