I m new to android programming and I am currently stuck on a big problem : Memory management.
Basically, my apps is trying to load 10 pictures (represented as byte[]) into 10 imageViews. The big problem is that (I think) decoding (via BitmapFactory.decodeByteArray()) and having 10 bitmap at once is extremely memory consuming so I get a memory error (OutOfMemoryError).
My question is more technical then trying to fix my code as I want to understand how it works and fix it after understanding what's wrong.
How can you get a Bitmap to take a small amount of space on RAM at runtime?
I m only loading 10 pictures but if I had to load 50 in a scroll view (not efficient I know, gridview is better but just for the purpose of the example) would it be possible ?
I have read the android documentation but it doesn't tell me how to take less space :/ I went through all the article of this section and loaded my bitmaps properly using the code given (load a scaled down version of my image through : https://developer.android.com/training/displaying-bitmaps/load-bitmap.html)
Right now, every Bitmap I load takes 20MB at runtime (way to much when limit is at around 130MB) and can I bring this down to less then 1MB by any technique?
Related
I'm building an application with very big sized images.
Almost all of my UI components are made of ImageViews.
I only have to show 12 images(ui components) on my first activity, but it consumes 80mb on startup.
The images are divided into each drawable directories using Android Drawable Importer.
By doing this I was able to reduce the runtime memory(which I can see on the Android studio's device monitor) to half, but it is still consuming 80~120mb of memories, which I believe is too much.
The first question is, isn't 80~120mb too much for a four screen(two activities, three fragments) application?
The second is, if it's too much then, what and how can I do to reduce memory usage?
When working with images keep in mind that there is a HUGE difference between compressed format (jpg, png..) and Bitmap. Computing the size of a Bitmap is pretty easy, it's width * height * 4 bytes (assuming that the bitmap has the default configuration argb888). So a full hd image that compressed is xy kb, when decompressed will occupy 8294400 bytes (~8mb). So my advice to reduce memory consumption is... scale down your images. You're asking if 80-120 mb is too much, well it seems like a lot but it really depends on what you're doing. What happen if you force garbage collection (there should be an icon in the device monitor)?Another thing to take into account is how to decompress the images, refer to this and use a library (Picasso, Glide..).
I'm getting an OutOfMemoryError exception thrown after a few loads of my apps main screen. The app loads data and a background image about a location. There are several options to choose from, and after 5-6 different location selections, the heap exceeds 192 MB and I get my error. I believe the issues is down to my using bitmaps poorly.
My code is quite long and unclear, so I'll give an example and hopefully someone can help me, as I think I'm failing to grasp the basics regarding image memory management (I have read documentation and searched extensively, I'm looking to ideally actually converse with someone about this).
I have an if with 5 conditions, each returns a different image.
I convert the image to a bitmap and set it as the new drawable source for my main layout.
Then I do this again, same function but for a different location, with a different image.
After a few times doing this, all these images being loaded seem to remain in the memory, and clog it up, leading to an error. Trying to keep it very simple, what steps should I be implementing between loading these different images into my layouts background to prevent this issue?
You have to recycle bitmaps, you are not using anymore. Make sure you are holding very limited number of Bitmap instances at the same time, and each time you finishing using a bitmap call its "recycle()" method.
You can find more information here: Managing Bitmap Memory & Caching Bitmaps
Hoping someone can help me solve this.
Im making a very simple game on android 4.2.2 using just UI elements, ie no 3D, opengl, Just as a challenge really but I've ran into a little head ache.
I was having O.O.M issues with loading graphics (to be expected with android) so i looked for other routes and found bitmap factory and decided to use a simple implementation. with my images i was hitting up to 40mb allocated memory during game play so I reduced the files from 1080x1920x4bit to 540x960x4bit in a hope to reduce memory load but now it reaches up to 72mb during game play.
Am i missing something or is me thinking, halve the size of images and halve the memory usage? or does upscaling use that much more?
is there any way I can reduce this amount of memory down to a decent 16-20mb range?
Notes on the APP.
all images are stored in res/no-dp or res/xxdpi. And are all jpegs.
I have six pop up images which are 100x100dp jpegs and 5 x Life segments which are 50x50dp
this is the code im using to load the images from bitmap factory
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.dummy1nn);
button7.setImageBitmap(bMap);
and im loading the other images as background resources for now via buttons or image views.
I also have soundpool running on elements and a timer.
Any help would be appreciated. I dont want to post all my code as it is a right mess at the minute as im trying many different methods to get this working smoothly. The only issue i have is the memory load.
My current memory after running the game and letting it sit for 5 minutes is:-
Heap size - 73.086mb
allocated - 70.40mb
free - 2.625mb
used - 96.41%
objects - 47,161
I'm using LG Nexus 5 'hammerhead' as DEV device with unlocked bootloader and stock rom.
Thanks guys. :)
edit:
Answer was to use picasso, although there are a few image libraries out there i liked the simplicity of picasso a lot. and always use MAT when using images to make the relevant changes to quality/size and format to get the lowest memory print (mine dropped to 26mb peak)
have fun
Picasso is a really good library that will handle memory management, asynchronous loading, and caching for you.
Using your example, it would be used simply like this:
Picasso.with(this).load(R.drawable.dummy1nn).fit().into(button7);
I am Working with one android tablet application in which lots of work with Images.
i have to load hundred of large bitmap images in scroll view. one image is around 1Mb to 3 Mb.
i have already scale images using bitmap factory and sample size, and also load all the images in Async task.
i am loading all the images from SD card.
Still facing OUT OF MEMORY issue after scrolling some images.
any help would be appreciated.
thanks in advance.
hi hope your solution.
you can user Univarsal Image Loader. This is better api for image download and store in catch. and get from catch. it's a great api for image operation.
this case is often come while we getting bitmap so just use lazy loading. just take a look on this example
http://sunil-android.blogspot.in/2013/09/lazy-loading-image-download-from.html
To prevent your application from soaking up CPU time without getting anything done, the JVM throws this Error so that you have a chance of diagnosing the problem.
Its because of large bitmap memory in stored in native area
so it better i suggest you use libraries like Universal Image Loader or
Bitmap Fun from android
You have to find out when the OOM error occurs. Is it when you have too much bitmap cache in memory without releasing or you just meet it when you're decoding certain bitmap?
For the first situation, I think you should manage your bitmap cache yourself or using some effective 3rd-party library which mentions above.
For the second situation, I've met it on some low-performance mobile(usually with 512MB or less memory), when you decode a bitmap to requested size, it may needs a rather large memory to store the bitmap, for 240dpi devices, it's about 800 * 480 * 4 = 1.5MB, however you may fail to allocate that much memory on some machines cause they may have strict memory manage strategy to prevent that much memory allocation. You should just catch the OOM error and continue rather than get a crush.
Loading a bitmap in 1280x800 display will take 1280x800x4 byte (~4MB) memory. Java heap size is limited (~50MB) so you can not use lots of large bitmaps in your app. Using cache and reusing bitmap objects are necessary while working with bitmaps but another useful trick is to use larger hip size! to do so, add android:largeHeap="true" to Application tag in your manifest. It increases hip size to 4 or 5 times larger (~250MB) than normal. I hope this help other people reaching this thread while they search!
I have a problem: (I wouldn't be here otherwise ;)
I am creating an app that has a feature for displaying "3D" models. This part is really a collection of images taken from many angles and allows the user to "rotate" the "model".
This idea is working fine, but the problem lie in the loading of the images.
I have found that there are two ways:
Load all the images into memory, and then simply switch them for the correct angle.
Load the images as we need them - we can load a few ahead of time.
However these have problems:
If I was lucky, the images would fit into memory, but they don't. They are about 1.5-2MB each and there are about 75-100 images per model. This brings the total size to about 115MB at the minimum.
If I was lucky, the image would load quicker than the user could "rotate", but they don't. The user can easily switch to an angle that is not loaded yet, resulting in a black screen for a few seconds.
I have created a loader that allows me to simply add the images that I need to a stack and the loader will then one-by-one load the images. This works fine if the user scrolls fairly slowly. My loader takes care of releasing memory when it is finished, so no matter how many images I load, the app usually won't crash as long as I specify the max images to store in memory. My loader can load the images very quickly, but there is still a few milliseconds (~250ms) for it to load the large image into memory.
Of course, the loader is on a different thread, and the loading in no way hinders UI response. That is why if the user swipes back and forth quickly, no image will actually display, as the loading and unloading are all working at the same time to result in no images :)
So, my problem: How do I provide a smooth and user-pleasing rotation of the images without loading all the images into memory?
Don't load (or store) resolution you don't need. If your user needs to zoom, an out-of-memory binary image pyramid is a cheap way to let you load only the level of zoom necessary. If your user needs to pan through an image larger than your display area, you can break your large image into smaller tiles, and only load the ones you need.
If you want to get fancy, you can write a UI-aware cache manager to preemptively load tiles you think you might need soon, and mark tiles you're pretty sure you won't need soon for preemption.
Better compression can fit more image data into memory, and speed up load time. So, pay attention to individual image compression, and don't load image quality you don't need, either.
As an extraordinary measure: since images from slightly different angles are similar to each other, you may be able to save time and space by representing the difference, instead -- look up lightfield compression. You will still need to convert from compressed form to a particular bitmap you can draw, but if the compression allows the dataset to remain in memory, you could potentially gain a lot of speed.
If you can't fit your compressed dataset into memory, there's a good chance the user will be able to swipe back and forth quickly enough to defeat your cache. So, if smoothness is your main goal, you could try for a "UI solution" by restricting the rotation rate (or the per-swipe rotation range?) to something your data loader can follow.
My only suggestion is for loading them efficiently. I assume that you are using techniques described here
If the images are of higher resolution than the screen you can calculate the sample size of the image you want to render then you can load an image that fits your screen rather than the full size image which will use much less memory. If you are already doing that then to me it seems like how you are doing it efficiently already. Perhaps you could show the user some kind of placeholder graphic while an image is loading so they won't just have blank space.
Thanks for the answers. I laughed at myself and then went to bed after reading the answers.
Let me share how I resolved this problem - it uses some pieces of the answers:
I was trying to cache the large images in memory - this is unnecessary, why not store a lower res version and then load the hi res when the user stops scrolling? Then the user can scroll as fast as he likes and there will always be images in memory to quickly paint. When the user stops/slows scrolling, we load the hi res image.
Because he will be scrolling fast, he won't be able to see the lower res' lower quality.
And, as there will only be one hi res to load, the ~250ms delay is hardly noticeable.
This really combines the best of both cases. And I can use the Android's methods for loading a lower res version of the Bitmap.