In my APP, Activity-A triggers another Activity-B. Activity-B triggers another Activity-C. Now the control return to the Activity-A from Activity-C Via Activity-B. The Activity-A uses the Bitmap image to draw as a background in its Canvas.
Question:
When I move from Activity-A to B, Do I need to recycle the bitmap variable (eg. background.recycle()) in onPause() method ?
Assume, I recycled the bitmap variable in onPause() method. Will this be a good approach to avoid OOM error ( keep in mind that the image has to be re-drawn when it comes back to Activity-A)
Do you get OOM errors? If not (since your bitmap is not big) then simply do nothing ... The docu says about the recycle method:
This is an advanced call, and normally need not be called, since the
normal GC process will free up this memory when there are no more
references to this bitmap.
So there is also a main difference between Android 2.x and Android 4.x. In Android 4 the bitmap memory is no longer managed natively, but is part of the normal java heap and works like every reference works: If the there is no reference anymore, then the garbage collector will collect the bitmap somewhere in the future.
Wherer is the right point to call recycle? Well the right point will be, when the Bitmap is no longer displayed on screen. so onPause could be a possibility, but keep in mind that you have to reload it (async) in onResume. So whats the problem with that approach? Once you have marked the Bitmap to be no longer needed by calling recycle() the bitmap is no longer useable, but probably has not been GC collected yet. So if the user jumps from Activty A to B and will return quickly, it's possible, that you have the same bitmap twice in memory, because the GC has not collected yet the first (recycled) bitmap.
So my tipp is: Try to reduce the bitmap size if you have memory issues. Use less quality bitmap (have a look at Bitmap Options). But I guess you need to try diffrent strategies to find the best working one for your app.
every time you don't need the bitmap recycle it. using
if method at least to avoid force closing in some cases.
if (null != bmp){
bmp.recycle();
}
and i advice you instead of sending the Bitmap between activities get its filename by using intent and pass it through your activities like this you will avoid re-drawing the bitmap in every activity and that will cause OOM for sure.
Related
I have an activity that uses recyclerView and for each item's view there is an Image.
I have used Garbage Collector GC() on Destroy as follows
recyclerView= null;
adapter=null;
Runtime.getRuntime().gc();
But the following thing happens while releasing memory
And When I start another activity that loads images from a remote host using Picasso It says
java.lang.OutOfMemoryError: Failed to allocate a 94784012 byte allocation with 4194304 free bytes and 87MB until OOM
I found an answer that works for me to overcome that OutOfMemoryError
by Increasing heap size for application But I still want to release and ensure that memory occupied by an Activity is released instead of going to increase heap size for app.Thanks in advance , please help to do that task.
The code that you are using in your onDestroy method is not needed there. If destroy is called your acitivity will be removed from the stack and is free for gc anyway with all the resources in it that are only referenced by the activity.
OnDestroy doesn't always get called that's why your method may not be called at all. You could try and explicitly call for finish() in activity then onDestroy will be called and see how the situation will change.But then the activity will be removed from stack.
Also to call for gc manually is supposed to be bad style. On Android the system nearly always knows when it is the best time to do a garbage collection. Most of the times an activity finishes garbage collection is triggered automatically.
I would look into resizing images you get from Picasso first as they just could be too big in general for you heap even if there is space.
Look into resizing options link
Seems the problem is related to huge images, try to not keep images in memory, load images only on demand(with some cache strategy)
Try to replace picasso with glide. Glide provides better memory performance https://medium.com/#multidots/glide-vs-picasso-930eed42b81d
Try to load all your images with closest context
https://stackoverflow.com/a/32887693/6193843
1)It is considered a good tactic to recycle all bitmaps and data at activity's OnStop method.
2)It's also considered a good tactic to use a retainer Fragment to avoid recreating data at every configuration change.
But I don't see how these two can be combined?
Let's say I use a fragment to load a bunch of bitmaps...At OnCreate I check if that Fragment is null or not to get it's data or to instantiate a new one to create them. If i recycle all my bitmaps at OnStop() then there will be nothing left retrieve at the configuration change cause all data will have been recycled.
So....I don't see any way to combine these two tactics. Am I wrong? And if not which of the two is best to use?
My case is about loading images from SD card folder. could be only one pic, could be 500...
and showing pictues isn't all my app does so after this activity there could a need for memory by some other activity.
From Managing Bitmap Memory:
On Android 2.3.3 (API level 10) and lower, using recycle() is
recommended. If you're displaying large amounts of bitmap data in your
app, you're likely to run into OutOfMemoryError errors. The recycle()
method allows an app to reclaim memory as soon as possible.
According to this you don't even need to call recycle on devices running API 11 or higher, so it may not really be a problem for you.
You also really don't need to recycle bitmaps if the app is being destroyed as the system is going to reclaim all memory the app is taking up to begin with.
Recycle is only needed if you are showing a massive amount of bitmaps or large bitmaps and need the memory reclaimed in your app while it's still running.
Another thing to note is with the strategy you're trying, you wouldn't clean resources in the Activity's onStop() but rather the retained Fragment's onDestroy(). OnDestroy() on a retained fragment won't be called on configuration change because the Fragment isn't ever being destroyed. Thus, your resources can stay in memory beyond your Activity's lifecycle and will be destroyed at the end of your Application's lifecycle.
Disclaimer: I read about 20 existing questions. Unfortunately none of them solved my problem.
I have an activity. This activity gets a Bitmap from a global/static class C and sets the bitmap to an ImageView. When the activity is finished and I try to reopen the activity, I get the java.lang.RuntimeException: Canvas: trying to use a recycled bitmap exception. I don't call Bitmap.recycle() at any point. Also, I do not delete the bitmap reference in class C. I tried the following but they didn't work:
Call ImageView.setDrawingCacheEnabled(false)
Before setting the bitmap for ImageView, make a deep copy (via Bitmap.copy() method)
Also, I put some log statements throughout the activity lifecycle. Inside onDestroy(), before calling super.onDestroy() I check and make sure that the bitmap is not recycled (through Bitmap.isRecycled())
How can I fix this issue?
The culprit turned out to be RemoteControlClient.MetadataEditor.apply(), it does call recycle() for bitmaps passed to it.
I had similar issue with ImageViews when reopening the activity (e.g. after screen is waked). The problem lies not in Bitmap itself, but in ImageView. My solution was to set ImageView's setImageBitmap to null on activity's onPause() and call setImageBitmap(theBitmap) on activity's onResume().
I have a ViewPager with a couple of fragments. In a fragment onCreateView,
I decode a couple of bitmaps that are assigned to fields in the Fragment class. If I try to swipe between the fragments, at a certain point the application gets an OutOfMemory exception (heap is exhausted).
Ok, this is a really bad practice, but, isn't the GC supposed to free memory before my application is killed?
Reassigning the Bitmap to the same field should cause the previous Bitmap to be released, am I wrong? On S4 I get the exception very soon.
Suppose you load a bitmap, lets say that is the first and then assign a new decoded second bitmap to the first, the first bitmap is not GC'ed when you decode the second one. GC will do it later whenever it decides. If you want to free memory ASAP you should call recycle() just before decoding the second bitmap. Src: here. And, go through Android's Managing Bitmap Memory article. Refer this too.
Fragments are kept in memory unless stated otherwise, so either you manually detach and dispose of fragments when swiping or mBitmap.recycle() when swiping.
Edit, code:
final FragmentTransaction fm = getActivity()
.getSupportFragmentManager().beginTransaction();
fm.replace(R.id.fragPlayerMain, playerFragment, "fragment").addToBackStack(null);
fm.hide(thisFrag);
fm.detach(thisFrag);
fm.commitAllowingStateLoss();
In the documentation, titled "Managing Bitmap Memory" you can find the following statement:
Caution: You should use recycle() only when you are sure that the bitmap is no longer being used. If you call recycle() and later attempt to draw the bitmap, you will get the error: "Canvas: trying to use a recycled bitmap".
So, what exactly means "no longer"?
I call setImageDrawable(drawable) in my fragments onCreateView(...) method. And I call recycle() on the drawable's bitmap in the fragment's onStop().
When the user now leaves the fragment by launching another activity the bitmap is recycled. But when the user comes back to the previous fragment, its onCreateView() is called again, resulting in a new call to "setImageDrawable(drawable)". And this throws:
IllegalArgumentException: Cannot draw recycled bitmaps
So, I still seem to be in the "no longer" context. When do I get a new bitmap, which is not recycled? Only after the fragment and its activity have been completely destroyed?
So, what exactly means "no longer"?
No longer means you are not going to use the same reference of Bitmap.
As you told you are recycling bitmaps on onstop(), try with this also inside your onStop()
if(bitmap!=null)
{
bitmap.recycle();
bitmap=null;
}
Bitmap and outOfMemory in android
Watch first 20 minuts of this official video if you want to make your day good - http://www.youtube.com/watch?v=_CruQY55HOk