Here look at the below code,
for (String path : all_path) {
bmp = BitmapFactory.decodeFile(path);
bitmapList.add(bmp);
}
and this code is driving me crazy. As in each iteration BitmapFactory.decodeFile(path) is called and driving memory to its pick as a result OutOfMemory exception occurs. I tried to use recycle() old bitmap in the loop before decoding new bitmap but it means no sense. I searched for the answer about using bitmaps in loop but failed to find one. What should I do? anyone help please.
You are adding all bitmaps to a List. However you are using the same reference variable bmp for all bitmaps so in each iteration they get replaced.
But in the List all the bitmaps are being added. If there are many bitmaps then it will eventually result in OutOfMemoryError
Better do not add all bitmaps in a List.
Try to recycle the bitmaps you are not using.
If you use all the bitmaps than add them to a cache and use them later.
Next when you want to replace one you will replace just one not all of them.
The change from below requires a bit more work but it works as I used it with a lot of bitmaps.
Please take a look here:
I implemented once something like this:
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Bitmaps can be huge. Why do you need to read them all to the memory? Normaly, you would read each bitmap on demand. Optionally, you can read thumbnails, which are much less memory demanding (BitmapFactory enables you to downsize the bitmap when reading - use BitmapFactory.Options, member inSampleSize).
Read this: http://developer.android.com/training/displaying-bitmaps/index.html
Related
I have a question (hope it is not stupid). Is getDrawable(int resId) slow ?
And is it faster than decoding resource with BitmapFactory ? And is it faster to call getDrawable(resid).getInstrinsicHeight() than decoding with Bitmap.Options with inJustDecodeBounds = true and than get the width ? I know that decoding of bitmaps is slow, and they consume a lot of memory, but what about getDrawable(int redId) and the result Drawable object ? It is allocate a lot of memory.
Thanks in advance.
Your Question is Similar to this one :
Efficient way of creating Bitmap out of Drawable from res (BitmapFactory vs Type Casting)
"You can take a look at the source code for Bitmap factory at http://source.android.com specifically the code for decodeResource.
I would reason that using BitmapFactory is preferred but in either case if you are decoding multiple bitmaps then you should call getResources() once and store the result for use as the resources argument for the functions."
Further, i would recommend you to go through 1st 2 articles here, to learn about the workaround for using either of these effficiently :
http://www.coderzheaven.com/tag/getdrawable/
One would think that the second approach would be more efficient but I can't say that I see any improvement using it. Is there a difference between the following two ? (memmory wise ofcourse)
Bitmap bm=MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
bm=cropAndScaleBitmap(bm);
//use bm
vs
Bitmap bm=MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
Bitmap b =cropAndScaleBitmap(bm);
bm.recycle();
//use b
Things to note here ...
Even though you have specified recycle, it will have any effect only
when the next GC is trigerred.
Other things to note
In pre-Honeycomb versions of Android the memory for bitmaps was (is) allocated from unmanaged memory.It will take at least 2 passes of GC to collect it. Another thing is - it is really difficult to trace - DDMS does not see it and neither does MAT.
Read this link https://developer.android.com/training/displaying-bitmaps/manage-memory.html. If api level >10,I don't think we need to call recycle.
Refer to this link ... It provides all details and the code sample for how to implement step by step.
https://developer.android.com/training/displaying-bitmaps/manage-memory.html
Hope this helps.
In your specific example (first one) you don't actually reuse the source, you just overwrite the value of the bm making it point to the new bitmap instead, in this case you can no longer call recycle on the source bitmap as you no longer have a reference to it.
I recommend using the second method to make sure the source bitmap is recycled.
I have done following things to handle my bitmaps in application:
LruCache for Bitmaps with size of 1/8 of memory
Using BitmapFactory.Options to calculate inSampleSize
Catching OOM when creating Bitmaps, calling evictAll and System.gc() there
Also there are AsyncTask decoding sometimes for Bitmaps
I use BitmapFactory.decodeFile and it looks like VM is not freeing Bitmaps fast enough from memory. I read somewhere that there might be bug using BitmapFactory.decodeFile so I tried to use BitmapFactory.decodeFileDescriptor, but there I randomly get following:
skia --- decoder->decode returned false
So is there something wrong with FileInputStream needed to fix here if I wan't to use BitmapFactory.decodeFileDescriptor or something else to do.
This has taken me too much time and I've read all solutions based on this and how Google advices Bitmap handling and I've come to dead end.
Thanks.
Using large Bitmap always there is a chance to get Out Of Memory Exception..
So to handle go through Android blog
http://developer.android.com/training/displaying-bitmaps/index.html
And always recycle the Bimap
ImageView mImage;
Drawable toRecycle = mImage.getDrawable();
if ( toRecycle != null && toRecycle instanceof BitmapDrawable ) {
if ( ( (BitmapDrawable) mImage.getDrawable() ).getBitmap() != null )
( (BitmapDrawable) mImage.getDrawable() ).getBitmap().recycle();
}
I ended up using SoftRefences with Bitmap here. Now I can see GC freeing my unused Bitmaps all the time when fast scrolling GridView which draws them.
Tested setting my LruCache size full memory size and still didn't get OOM.
Penalty using this method is not that visible, my GridView scrolls pretty smoothly considering it's drawing very custom image.
System.gc() won't help you and doesn't guarantee anything.
If you absolutely sure, that evicted bitmaps are no longer needed and there is no reference to them anywhere (will catch "Can't draw recycled bitmap" exception otherwise) I would suggest you to add an EvictionListener to your LRU cache and call bitmap.recycle() on every evicted value.
Can't remember if default LRU cache provides convenience methods for setting eviction listener, but if not, it's extremely easy to extend it and add required functionality.
P.S. I would advice against WeakReferences since you lose any control of your bitmaps and purpose of LRU. Even if you load 8 bitmaps that nicely fit in your 1/8 of memory, but screen can only display 4 of them at a time (ImageViews holding a strong references to Bitmaps) gc will clear remaining 4 as soon as possible. And I really mean ultra fast. You'll have to reload bitmap for each new row (in case of ListView) you are displaying. And every bitmap that went offscreen will have to be reloaded again.
First, I use AsyncTask to download bitmap and contain bitmap into array.
myBitmap[0] = task.execute().get();
My first question is, if I recycle() my array of Bitmap and download by using
ASyncTask again when start Activity, This would cause any problems to memory or not.
Because if I download all Bitmap into my device, errors would occur surely. That's why I
have to download and remove them again and again.
And second question is, If I have some Bitmap as follows:
Bitmap newBitmap = myBitmap[0];
Do I have to recycle() the newBitmap to decrease memory?
Yes, I think you will have to call recycle to decrease memory usage. You could do it
1. when overwriting an existing bitmap location
2. releasing all bitmaps when exiting the app
3. Keeping tabs on number of bitmaps loaded at one time.
I suggest using an LruCache to manage the bitmaps. Helpful when keeping tabs on which bitmap is used most frequently etc.
In my Android app, when I run one of my activities a second time, I get an OutOfMemoryError. I think I need to delete the bitmaps from the first time when the activity runs. But I don't know how I can do this. Thank you.
Try reading your Bitmaps from within your code. Place the Bitmaps in the res/drawable-hdpi folder. (there are different folders for different image qualities). Set up the Bitmap fields in your code:
Bitmap alpha;
Bitmap foo;
Now initialize the Bitmaps in the onResume():
Options options = new Options();
alpha = BitmapFactory.decodeResource(game.getResources(), R.drawable.youBitmapName, options);
foo = BitmapFactory.decodeResource(game.getResources(), R.drawable.youBitmapName2, options);
Options will give you the ability to downsample. (I'm not sure how big your images are, but you might also want to use the scaling methods then).
In the onPause, clean up resources by calling:
alpha.recycle();
alpha = null;
foo.recycle();
foo = null;
As soon as the onResume() method is called, the bitmaps will reinitialize.
Normally the garbace collector would call Bitmap.recycle() as soon as no more references point to that instance.
If you want to 'force' clean up your bitmaps, call recycle() on your own.
But I would suggest to look for a memoryleak first.
Null your bitmaps and call the Garbage Collector: System.gc(); and/or Runtime.getRuntime().gc();
Also provide more details about your code for better answers.