I have two activities: MainActivity
and Activity2
.
The MainActivity simply open the seconds one through Intent.
To return to MainActivity
from the Activity2
I press the "back" button.
When I do these steps, the App crashes:
MainActivity
appearsActivity2
appearsMainActivity
appearsIntent
: my App crashes because of this error:
IllegalArgumentException: Cannot draw recycled bitmaps
MainActivity.java:
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
Activity2.java:
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
for(Map.Entry<Integer, ImageView> entry : mapImageViews.entrySet()) {
ImageView imageView = entry.getValue();
Drawable drawable = imageView.getDrawable();
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
if(bitmap != null) {
bitmap.recycle();
}
bitmapDrawable = null;
bitmap = null;
}
imageView.setOnClickListener(null);
imageView.setImageDrawable(null);
imageView.setImageBitmap(null);
imageView = null;
drawable = null;
}
mapImageViews.clear();
mapImageViews = null;
}
Since the application uses high resolution images (already adapted with BitmapFactory
and inSampleSize
), to avoid memory leaks I invoke recycle()
in the onDestroy()
method.
As I learned by reading lots of SO answers and on the Web, calling recycle()
on bitmap let they to be garbage collected early.
But many other posts advise against invoking recycle()
, or at least advise doing it only when you are sure that the bitmap is no longer needed in the Activity, that is in the onDestroy()
method.
Now I'm a little worried about what I've learned about it because if I remove the recycle()
the error no longer happens.
The error occurs on a device with Android 4.4.2
, but it does not occur on a device with Android 6.0
and on Nexus 7
(Android 5.1.1
).
try changing your onDestroy
method like below
@Override
protected void onDestroy() {
for(Map.Entry<Integer, ImageView> entry : mapImageViews.entrySet()) {
ImageView imageView = entry.getValue();
Drawable drawable = imageView.getDrawable();
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
if(bitmap != null) {
bitmap.recycle();
}
bitmapDrawable = null;
bitmap = null;
}
imageView.setOnClickListener(null);
imageView.setImageDrawable(null);
imageView.setImageBitmap(null);
imageView = null;
drawable = null;
}
mapImageViews.clear();
mapImageViews = null;
super.onDestroy();
}
Also see this: How to recycle and reuse images in an effective way.
According to the documentation for recycle
The bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap.
I cant see how you are assigning your bitmaps
to your ImageView
, but I assume you are trying to reuse the bitmaps when you start the intent again after they have been recycled
. I only ran into the exception if I was using android:src=
. If I set the ImageView
bitmap using the following in oncreate
, it ran fine on all targets you listed without throwing an exception.
imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.lake_park));
I highly recommend using glide to work with images. https://github.com/bumptech/glide
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With