Actually I have for so long wish to know how to present graphics in a proper way.
In an activity, I have the following:
a background (png, full screen, 768*1280, 1.36MB)
3 icons (each icon has pressed and not pressed: 2 states, using 1 png 400 * 400, 300KB each), i.e. 3 icon * 2 pic * 300KB = 1.8MB
some more textviews
When the app starts off and directly goes to this activity, everything is ok, the activity can be presented properly.
Yet somehow when the app has run for some other activities, and then goes to this activity through a dialog box, then most of the time errors will occur, as follows:
Out of memory on a 15728656-byte allocation.
Question:
I have researched for sometime and some say to bitmap.recycle(), yet how to implement? through the onCreate? or actually 400*400 is too big?
If I want to change the background of an activity upon users' choice, i.e. when he presses button A, the background changes to bgdA, presses button B will change background to bgdB... in that way how that can be achieved?
Many thanks!
Depending on where your asset is stored is the amount of memory it might take, since scaling factor is calculated between the difference of densities, this is a little gray area because I haven't found any official android documentation that backs this info up, however I've seen that error so many times and this is the way I handle it.
1.- If you don't have the asset in the proper drawable-(density), this will cause problems because depending on the devices you are actually supporting, you should put the asset in drawable-xxhdpi or drawable-xhdpi, you will notice how the memory will decrease considerably
2.- If you don't want to mess with densities because it's a generic image which don't have much details(like a simple background), then add the asset in the drawable-nodpi folder, it will prevent android from trying to scale the asset it self..
3.- As good practice, try to create the asset with the proper size for the proper densities, 400 x 400 seems like too much for an icon, this will also prevent you from OOM, not only in this activity, but for other activities that might also need to load a good amount of assets, giving scalability to your app..
Always take on count that leaving the "resize" of an Image to the OS might cause huge amounts of memory allocated because the OS will try to resize it based on the formula width * height * 4bytes, the 4 byes are for ARGB of each pixel, 1 byte per color or alpha, so if your image is for example 1090 * 1920, it could easily become internally 8.3MBs even tho the actual image size is only a few KBs, and if it tries to scale it, it might double it's size too.
Hope this Helps
Regards!
Make sure you have a copy of your image for every drawable folder in you res, for example if you runnig your app on the S4 phone and you don't have all the images in the drawable-xxhdpi folder you will run out of memory even with reasonably small images.
Also if you need to change background at run time use setBackgroundResource.
Hope it helps
This is the common problem in android here is the proper solution
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
In easy words you have to scale the image down according to your requirement
Related
I am using a button with a png background for CopyToClipboard function in my app (used about 6-7 times in various fragment). Since the image should be small for my purpose, I increased the area of my image by putting in extra transparent area around the image so that I could increase the button size for clickable area but keep the image small (I know its not efficient and since then I have devised better way to achieve this).
I noticed the huge spikes later on afterwards when uploading some other images (big images about 150kb size), and after a lot of debugging (and I do mean a lot!) I found that the problem was not due to the bigger images but due to the CopyToClipboard image which was of just 8kb in size!!! Changing back to older CopyToClipboard image (having lesser Transparent area) brought the memory consumption back to normal.
My question is why did that happen? For such a small image to create such huge spikes (more than doubled the memory consumption from previous) and made the app slow, is quite baffling.
Image shown below : The White area is the transparent area. My button dimension : 15dp x 15dp .
I repeat, My question is why did that happen? Not a solution for it since I already solved the problem.
It doesn't really matter that your image is only 7-8KB on disk, because it will take much more memory when it's decoded.
Apparently, large transparent area can be efficiently encoded in PNG file, so the image has that small size.
But in fact, it's dimension is (600 x 745), so in memory it will take roughly (600 * 745 * 4) bytes, plus some meta information, so nearly 2 megabytes. 4 multiplier stands for an amount of bytes needed to encode color with alpha channel.
Android Bitmaps are represented internally by linear one-dimensional array of integers, so you can imagine that system needs to allocate an array with size 600 * 745 = 447000 to create your Bitmap.
That's why memory consumption is so high for such a simple image.
My app keeps crashing due to an "Out of memory" exception. I'm almost positive that it has something to do with all of my images used within the app. I threw them in my drawable folder in the beginning without ever considering their size. For example, I use a background .png image in all of my Fragments. It's size is 832x561. Is that too large for say a standard android phone like a nexus 5? Is there a reference chart for appropriate image size based on device? Thank you.
I'm trying to detect my memory leaks.
After watching the video from Google and reading on StackOverflow, I'm starting to give it up because I don't find the issue.
My first Activity loads 4 images from resources (ImageView, for each one the width in pixels are not bigger than 400px), and I can find this on MAT (MainActivity):
then if I start the HomeActivity, this has more imageviews but all of them are short and small. So I load it and I get this:
but if I use regex with HomeActivity or MainActivity:
And this, are supposed to be my LEAKS:
I tried to not to set some images, delete an horizontalScrollView, deleting some items which could be a problem.
And I'm totally lost. Would you know what I'm doing bad?
Thanks in advance.
My first Activity loads 4 images from resources (ImageView, for each one the width in pixels are not bigger than 400px)
First, an ImageView is not a resource. It is a widget.
Second, the size of the ImageView is irrelevant by default when it comes to loading resources.
and I can find this on MAT
You are consuming ~26MB worth of heap for byte[]. If you expand that node in the tree you should see specific instances of this. If you find one of interest, right-click on it and examine its GC roots to try to identify what it is.
So I load it and I get this
This shows two specific byte[] at ~12MB and ~11MB each. Right-click on them and explore their paths to GC roots to try to identify what it is.
Would you know what I'm doing bad?
Not specifically. After all, we do not have any Java code, any resource XML, or anything much to go on.
If I had to guess, you added some large image files as drawable resources and are relying upon ImageView to scale them down to smaller sizes. That's fine, but ImageView does not reduce the heap used by the images themselves. That will be determined by the resolution of the image (width * height) and the bit depth of the image (usually 4 bytes per pixel for ARGB_8888). Resources are never released once loaded, compounding your problem. You can:
Scale the image yourself at compile time to something closer to what you will actually need at runtime, and/or
Use BitmapFactory and decodeResource(), with an appropriate BitmapFactory.Options instance and inSampleSize value, to load the image in more manually, downsampling it at runtime to consume less heap space, and loading it as a regular Bitmap (AFAIK, decodeResource() does not load the resource as an actual resource, allowing it to be better managed at runtime)
In my game I have 3 activities: Main menu -> Sub-menu -> Game screen. So when user is playing in the Game screen, first two activities are inactive, but not destroyed.
There is a nice background image in each layout. The image itself is quite small (40k), but on large screen (say Galaxy tablet), it takes up to several megs of memory.
After removing background from first two activities, memory usage in third activity falls from 18M to 13M!
Is there any way to keep backgrounds and to recover all this wasted memory?
I have experienced a similar issue due to background images in layouts. The normal size of a memory allocation of an image should be height*width*4 bytes (in mode ARGB_8888, the default mode).
If you see and allocation of 18MB when showing an activity there must be some problem. Check if you are placing your background images in the drawable folder. In that case, the system must scale that image to the specific density of the screen, causing a big memory overhead.
Solutions:
Place a specific version of the background image in each drawable folder (mdpi, hdpi, xhdpi...) so the system does not have to perfom any scaling process.
Place the background image in a special resource folder called "drawable-nodpi". The system won't try to scale images placed in this directory so only an streching process is carried out and the memory allocated will be the expected.
More information in this answer
Hope this helps.
Why dont you finish the previous activities when starting the new activity (C).
Then you can override the onKeyDown method in activity C to start the previous activity (B)
I think my problem is same to yours, this solution will help you.
Why does the normal pictures allocated a lot of memory?
You can use /res/drawable-nodpi, the background pictrue only take half of the memory size.
I would suggest to override onPause() or onStop() in your activity. In there, you can release the background (by calling layout.setBackgroundDrawable(null))
I have a graphic designer that helps me with UI development. We start with me taking screenshots of my current UI using my Nexus One (800x485). Then he overlays new art over the old screenshots in Photoshop and creates transparent PNGs. Then I take that, plug it in my app and to my dismay these images appear big and blurry (about 35% larger). When I check images these are created at 72 dpi so I really have no idea why this is happening. Any ideas?
You need to put the graphics in the correct configuration directory for the target screen. If they are being designed for N1, that 800x480 screen is a high density screen, so the graphics need to go in drawable-hdpi. Not in the generic drawable directory, which for backwards compatibility is assumed to be mdpi.
I edited my answer since it was not the correct one.
Other idea, how are you handling your draws ?
(if your using a custom view draw you could post the code if this doesn't help).
I'm asking because there is a trap while drawing with the dimensions:
are you using
bitmap.getScaledWidth
instead of
bitmap.getWidth
that could lead to imprecise/bigger images.
The current idea I have in mind is: (easier to explain with an example):
you have an image of 100*100
you display
you capture it
you edit it and make it pretty
you reinject it
you display it but because your on a high res the dp scales it and it gives it a bad aspect
I don't know if I'm being very clear. but if your using a custom view for your display then you should check your scales.