Error de falta de memoria de ImageView

Soy nuevo en la programación de Android y tengo un error que dice que mi aplicación se queda sin memoria, este ejemplo he copiado de un libro y que está trabajando con resolución de imágenes pequeñas, pero cuando he añadido algunas fotos con una resolución más grande De error de memoria aparece, puede ser que hago algo mal o simplemente no sé todo lo que todavía debe trabajar con imágenes, si alguien sabe qué debo cambiar para que este error no volverá a aparecer, súplica ayuda. ¡Gracias anticipate!

El código fuente:

public class ImageViewsActivity extends Activity { //the images to display Integer[] imageIDs={ R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5 }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final ImageView iv=(ImageView) findViewById(R.id.image1); Gallery gallery=(Gallery) findViewById(R.id.gallery); gallery.setAdapter(new ImageAdapter(this)); gallery.setOnItemClickListener(new OnItemClickListener(){ public void onItemClick(AdapterView<?> parent, View v, int position, long id){ Toast.makeText(getBaseContext(), "pic"+(position+1)+" selected", Toast.LENGTH_SHORT).show(); //display the image selected try{iv.setScaleType(ImageView.ScaleType.FIT_CENTER); iv.setImageResource(imageIDs[position]);}catch(OutOfMemoryError e){ iv.setImageBitmap(null); } } }); } public class ImageAdapter extends BaseAdapter{ private Context context; private int itemBackground; public ImageAdapter(Context c){ context=c; //setting the style TypedArray a = obtainStyledAttributes(R.styleable.Gallery1); itemBackground = a.getResourceId(R.styleable.Gallery1_android_galleryItemBackground, 0); a.recycle(); } //returns the number of images public int getCount() { // TODO Auto-generated method stub return imageIDs.length; } //returns the ID of an item public Object getItem(int position) { // TODO Auto-generated method stub return position; } //returns the ID of an item public long getItemId(int position) { // TODO Auto-generated method stub return position; } //returns an ImageView view public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ImageView iv= new ImageView(context); iv.setImageResource(imageIDs[position]); iv.setScaleType(ImageView.ScaleType.FIT_XY); iv.setLayoutParams(new Gallery.LayoutParams(150,120)); iv.setBackgroundResource(itemBackground); return iv; } }} 

ERROR AQUÍ:

 04-18 10:38:31.661: D/dalvikvm(10152): Debugger has detached; object registry had 442 entries 04-18 10:38:31.661: D/AndroidRuntime(10152): Shutting down VM 04-18 10:38:31.661: W/dalvikvm(10152): threadid=1: thread exiting with uncaught exception (group=0x4001d820) 04-18 10:38:31.691: E/AndroidRuntime(10152): FATAL EXCEPTION: main 04-18 10:38:31.691: E/AndroidRuntime(10152): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.nativeCreate(Native Method) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createBitmap(Bitmap.java:499) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createBitmap(Bitmap.java:466) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:371) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:539) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:508) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:365) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:728) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.content.res.Resources.loadDrawable(Resources.java:1740) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.content.res.Resources.getDrawable(Resources.java:612) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.ImageView.resolveUri(ImageView.java:520) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.ImageView.setImageResource(ImageView.java:305) 04-18 10:38:31.691: E/AndroidRuntime(10152): at image.view.GalleryView$ImageAdapter.getView(GalleryView.java:95) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.makeAndAddView(Gallery.java:776) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.fillToGalleryLeft(Gallery.java:695) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.trackMotionScroll(Gallery.java:406) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery$FlingRunnable.run(Gallery.java:1397) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Handler.handleCallback(Handler.java:618) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Handler.dispatchMessage(Handler.java:123) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Looper.loop(Looper.java:154) 04-18 10:38:31.691: E/AndroidRuntime(10152): at android.app.ActivityThread.main(ActivityThread.java:4668) 04-18 10:38:31.691: E/AndroidRuntime(10152): at java.lang.reflect.Method.invokeNative(Native Method) 04-18 10:38:31.691: E/AndroidRuntime(10152): at java.lang.reflect.Method.invoke(Method.java:552) 04-18 10:38:31.691: E/AndroidRuntime(10152): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:917) 04-18 10:38:31.691: E/AndroidRuntime(10152): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674) 04-18 10:38:31.691: E/AndroidRuntime(10152): at dalvik.system.NativeStart.main(Native Method) 

Utilizar

 ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle(); 

¡Antes de cambiar a la nueva imagen !!

Para añadir a la respuesta de Ken, que es un pedazo de código sólido, pensé que iba a derribarlo después de que lo configuró:

  if(imageView != null) { ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle(); } imageView = (ImageView) view.findViewById(R.id.imageView); imageView.setImageResource(resID); 

NOTA: Esto no funcionará si está intentando intercambiar una imagen que ya ha reciclado. Obtendrá algo como esto en LOGCAT

Lona: intentando usar un mapa de bits reciclado

Así que lo que hago ahora si no tengo que cargar un montón de diferentes imágenes asincrónicamente, simplemente pongo esto en onDestroy cuando se trata de fragmentos y grandes imágenes de fondo:

 @Override public void onDestroy() { super.onDestroy(); imageView.setImageDrawable(null); } 

Las imágenes vienen en todas las formas y tamaños. En muchos casos son más grandes de lo requerido para una interfaz de usuario de aplicación típica (UI). Por ejemplo, la aplicación Galería del sistema muestra las fotos tomadas con la cámara de tus dispositivos Android, que suelen tener una resolución mucho mayor que la densidad de pantalla de tu dispositivo.

Dado que usted está trabajando con memoria limitada, idealmente sólo desea cargar una versión de baja resolución en la memoria. La versión de resolución inferior debe coincidir con el tamaño del componente de interfaz de usuario que lo muestra. Una imagen con una resolución más alta no proporciona ningún beneficio visible, pero aún así ocupa una memoria preciosa e incurre en sobrecarga de rendimiento adicional debido a la escalada adicional en marcha.

Fuente: Cargando mapas de bits grandes eficientemente

Sobre la base de la información anterior te recomendaría en lugar de configurar la imagen como esta:

 setImageResource(resId); 

Para establecerlo así:

 setScaledImage(yourImageView, resId); 

Y copiar y pegar los métodos a continuación:

  private void setScaledImage(ImageView imageView, final int resId) { final ImageView iv = imageView; ViewTreeObserver viewTreeObserver = iv.getViewTreeObserver(); viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { iv.getViewTreeObserver().removeOnPreDrawListener(this); int imageViewHeight = iv.getMeasuredHeight(); int imageViewWidth = iv.getMeasuredWidth(); iv.setImageBitmap( decodeSampledBitmapFromResource(getResources(), resId, imageViewWidth, imageViewHeight)); return true; } }); } private 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); } private 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; } 

Para aquellos que usan la librería de carga de imágenes de Glide , que todavía se están ejecutando en estos OutOfMemory Exception , hay muchas cosas que puede hacer para que Glide utilice menos memoria y, con suerte, solucione su problema. Éstos son algunos de ellos:

  • No utilice android:scaleType="fitXY" dentro de su ImageView . Así que si eres ImageView ve así:

     <ImageView android:id="@android:id/icon" android:layout_width="@dimen/width" android:layout_height="@dimen/height" android:adjustViewBounds="true" android:scaleType="fitXY" <!-- DON'T USE "fitXY"! --> /> 

    Cambie el ImageView para usar un android:scaleType diferente android:scaleType , preferiblemente: fitCenter o centerCrop .

  • No utilice wrap_content en ImageView , use match_parent o especifique el width / height explícitamente usando un tamaño en dp . Si usted realmente insiste en usar wrap_content en su ImageView , al menos establecer un android:maxHeight / android:maxWidth .
  • Desactive las animaciones con: dontAnimate() en su Glide.with()...
  • Si está cargando lotes de imágenes potencialmente grandes (como lo haría en una lista / cuadrícula), especifique una thumbnail(float sizeMultiplier) carga en su solicitud. Ex:

     Glide.with(context) .load(imageUri) .thumbnail(0.5f) .dontAnimate() .into(iconImageView); 
  • Glide.get(context).setMemoryCategory(MemoryCategory.LOW) temporalmente la huella de memoria de Glide durante ciertas fases de la aplicación mediante: Glide.get(context).setMemoryCategory(MemoryCategory.LOW) .

  • Sólo hay caché en la memoria si es necesario, puede apagarlo con: skipMemoryCache(true) en su Glide.with()... Esto todavía almacenará en caché las imágenes en el disco, que usted deseará probablemente puesto que usted está renunciando al escondrijo en memoria.
  • Si estás cargando un Drawable de tus recursos locales, asegúrate de que la imagen que estás intentando cargar NO ES SUPER HUGE. Hay un montón de herramientas de compresión de imágenes disponibles en línea. Estas herramientas reducirán el tamaño de sus imágenes al mismo tiempo que mantendrán su calidad de apariencia.
  • Si la carga desde recursos locales utiliza .diskCacheStrategy(DiskCacheStrategy.NONE) .
  • Enganchar a la devolución de llamada onTrimMemory(int level) que Android proporciona para recortar la caché Glide según sea necesario. Ex.

     @Override public void onTrimMemory(int level) { super.onTrimMemory(level); Glide.get(this).trimMemory(level); } 
  • Si visualiza imágenes en un RecyclerView puede borrar explícitamente Glide cuando las vistas se reciclan, así:

     @Override public void onViewRecycled(MyAdapter.MyViewHolder holder) { super.onViewRecycled(holder); Glide.clear(holder.imageView); } 
  • Si esto sigue ocurriendo, incluso después de haber "probado todo", el problema podría ser su aplicación (GASP!), Y Glide es sólo la única cosa que está empujando a la zona de OutOfMemory Exception … Así que asegúrese de que no No tienen fugas de memoria en su aplicación. Android Studio proporciona herramientas para identificar problemas de consumo de memoria en su aplicación.
  • Por último, compruebe la página de problemas en GitHub de Glide , para problemas similares que pueden proporcionar información para solucionar su problema (s). El repo se maneja muy bien y son muy serviciales.

Google tiene la respuesta correcta (perfecta):

https://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Un ejemplo de cómo lo uso en fragmentos:

 private ImageView mImageView; private View view; private int viewWidth; private int viewHeight; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_episode_list, container, false); mImageView = (ImageView) view.findViewById(R.id.ImageView); ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); viewWidth = view.getMeasuredWidth(); viewHeight = view.getMeasuredHeight(); mImageView.setImageBitmap(Methods.decodeSampledBitmapFromResource(getResources(), R.drawable.YourImageName, viewWidth, viewHeight)); } }); } return view; } 

Pongo estos métodos de Google a mi clase "Métodos" (a cualquier otro método útil):

 public class Methods { ... 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; } 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); } } 

Puede dejarlo en bibliotecas de terceros como Glide

 // imageView.setImageResource(imageId); Glide.with(this) // Activity or Fragment .load(imageId) .into(imageView); 

A continuación, le indicamos cómo añadirlo a su build.gradle :

 compile group: 'com.github.bumptech.glide', name: 'glide', version: '3.7.0' 

Picasso de la plaza lo hace también Picasso carga los recursos dibujables de su URI

Tuve el mismo problema cuando estaba mostrando la imagen grande en la imagen en modo de paisaje. Así que me resolví usando este código

  File imgFile = new File(imageFile.getAbsolutePath()); // path of your file FileInputStream fis = null; try { fis = new FileInputStream(imgFile); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; options.inPurgeable = true; options.inScaled = true; Bitmap bm = BitmapFactory.decodeStream(fis, null,options); profileIV.setImageBitmap(bm); } 
  • Necesita ayuda para comprender la pérdida de memoria en mi aplicación de Android
  • OutOfMemoryError: Usando una imagen que es 1080 * 1920 haga la página de bienvenida
  • Android Robolectric Gradle - java.lang.OutOfMemoryError: PermGen espacio
  • Métricas de memoria en aplicaciones Android
  • Error de memoria de mapa de bits - Android
  • OutOfMemoryError al cargar imágenes en RecyclerView
  • Subir archivo grande con barra de progreso y sin Error OutOfMemory en Android
  • Error de OutOfMemory de Android y LruCache
  • HttpClient.execute lanzando OutOfMemoryError
  • Fuera de la excepción de memoria en gson.fromJson ()
  • ¿Cómo puedo graciosamente degradar mi rendimiento, dada la memoria limitada?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.