The Infamous "Exceeds VM Budget" Issue - android

So I have an APP that loops and continuously draws many png files to a canvas. In the constructor for the thread, for some of the pngs I declare Drawable and some Bitmap handles and assign them (respectively) like so:
Drawablename = context.getResources().getDrawable(R.drawable.pngresource);
mBackgroundImage = BitmapFactory.decodeResource(res, R.drawable.bckgrnd);
Keep in mind I do both methods, MANY times. (even though most of the images are fairly small)
Well... the problem i'm getting is that when trying to start this app on older devices (specifically like the original droid and older) it force closes with the VM budget error.
From research, I've noticed that this seems to be a common problem. (The app runs fine on all newer devices such as droid x, every tablet at best buy, charge, atrix, etc.)
So my question is could I be doing something better?
Is one of these methods of referencing the pngs superior?
Also What exactly is happening here? I need to be able to reference the Image to draw at any time. In other words, at any given instant I could call Draw on one of the handles.
The fixes I've seen for similar problems involve calling the Garbage collector, but would that help me since I would need the Images later anyway? Or is this exclusively a problem with the way i'm referencing the pngs from the drawable folder?
Sorry if this is confusing, i'm a beginner.
If I called System.gc() after every reference would that help, even though the reference is still stored as a Drawable object?

The common fix:
Resize image size, for example: createScaledBitmap()...
Reduce image quality, Config.inSampleSize setting...
Remove all references to Bitmap objects when un-used (setting references to NULL, of course). If you don't do this, System.gc() will does nothing, remember this! and this method call does not guarantee that the memory will be freed right away.

Related

Memory management when changing src for ImageView

I am still new to Android, and never had to deal with memory management in my previous experience.
In my android application, I have an activity with a TextView, a ListView, and ImageView. I have listeners for the textview and listview, and the code that changes the contents in all three of those views. The contents is stored in the arraylist. The source for the ImageView is stored in form of a String (filenames), and the code that makes the changes looks like this:
tv1.setText(myText);
imgView.setImageResource(myImage);
This worked perfectly well while I only had a few images to test the logic, but once I added more images, I started to get the OutOfMemory error. If I make the images smaller, I get that error a little later in the process, but I still get it.
At first, I thought that Android does not release the previous source, so I thought using recycle() before the reassignment will help. Instead, I've got another error when I try to change the source:
Cannot draw recycled bitmaps
It looks like I am missing some vital understanding about how the ImageView handles the source images. Does it assign the bitmap reference and then keeps the same reference, but somehow changes content?
Then, after reading this article, I realized I have a different kind of problem altogether, the one that might be solved by using the inBitmap. Yet, the documentation says the bitmaps have to be the same size for that, and mine are not.
I am thinking of converting my drawable to bitmap, then scaling it to some hard-coded dimensions, then using inBitmap. I guess my second question is - does this approach make sense? Are there any downfalls in scaling the images? And any examples would be appreciated, of course.
Thank you!

Calling setImageViewBitmap on RemoteViews causing incredible lag

I am creating notification with music controls.
Everything is fine except artwork update.
The original artwork Bitmap is like 1024x1024 pixels or around so. If I call setImageBitmap(, ) for my RemoteViews directly, it causes lags.
If I'm trying to create new, smaller Bitmap via Bitmap#create(), then there is still lag.
So, what am I doing wrong?
Brett is right. However, it looks more like a bug than a feature.
Instead of re-using the same RemoteViews with different bitmap, I re-create RemoteViews every time with new Bitmap and then send it to a Notification. Strangely, this doesn't cause much lag.
I have run into this as well. SetImageBitmap is expensive as it must marshal the bitmap across the IPC boundary. This requires a large alloc in order to store the bitmap in the IPC message, then there's the actual marshaling of a large blob of memory. You will almost always see a GC_FOR_ALLOC message every time you use setImageViewBitmap. And that is a preemptive GC (world-stopping) which is probably where your lag is coming from.
Ideally, you should use setImageViewUri with a file:// Uri, this alleviates the above IPC concerns and is reasonably fast.
So, bottom line, is that if you are setting bitmaps of any significant size (i.e. larger than a small icon), you will see this lag.

Android OutOfMemory exception - Is there another approach for my needs?

My app is loading a large image (a house floorplan), then drawing touch-reactive objects (furniture, lamps etc.) on the image. I have a base image file included with my app but the objects come from coords in my database.
I've successfully deployed the app in multiple iterations, but now I need to use larger base images and BitmapFactory is causing an OutOfMemory exception on many devices (both old and new devices; anything with < 32MB heap seems to crash). I've read the 157 OOM questions on SO, but I'm afraid the link they all seem to point to won't help me since resolution / zooming is critical to the app's function.
I've tried to test the device's available memory before loading, but the results are spotty at best (some devices like the galaxy S3 report plenty of heap but still crash). I've also tried decreasing resolution but the image became unusable when reduced to a safe size based on the above test.
Is there another way to implement this design without ever using bitmaps?
I need to:
Load large base image
Create clickable shapes on top of the base image, maintaining their position / scale relative to the base image
BONUS: in the iOS version of my app, I can do SVG-style text scaling so a long label on a small object will stay inside the object
instead of running across the map(and will be invisible until the
image is zoomed). Replicating this in android would make me a happy
code monkey.
I can post code if needed, but you've all seen it before (almost all of it came from SO).
Thanks in advance for reading, and for any help you can give.
you have a few options:
break your large image into tiles, load these tiles into an array, and move a camera object around and only load tiles that need to be drawn, as the comments suggest.
make your image small and scale it up using 'android:scaletype`
Draw lines and curves on a Canvas object at runtime.
Use OpenGL
The appropriate solution really depends on how you want it to look. Tiling will take more dev effort but will look better, just be careful that you are properly cleaning up any tiles that aren't being drawn...
dynamically scaling will be easier, but you cannot guarantee the image won't be blurry.
Drawing on a Canvas object at runtime could work well-- just use Lines of different width and circles and Rects etc.
Using OpenGL will have the steepest learning curve, and might be overkill. This depends on your purpose.
You might like to look into using a "largeHeap"
http://developer.android.com/reference/android/R.styleable.html#AndroidManifestApplication_largeHeap
Here are some options:
1) Use tiles. Use tiles and dynamically load your data. Honestly, this is the best solution. With this solution you can load arbitrarily large images.
I've successfully used this approach for an endless paint canvas and it works quite well. You really only need to draw what is directly visible to the user. Tiles is a way to cast away pieces you don't need. A pyramid of tiles (where you pre-downsample your images and create more tiles), allows you to do this in a clean and fast way.
2) Use native code. The memory restrictions on native code are not the same as Java code. You can get away with allocating more memory.
3) Use OpenGL. Once again, the memory restriction for OpenGL are not the same as Java code.
4) Convert your original plan to an SVG and use an SVG library like this one.
5) Use "largeHeap". I strongly discourage this, as I think a largeHeap is rarely the solution, there are generally cleaner ways to approach the problem.
if the image is static , you might wish to use this nice library:
https://github.com/ManuelPeinado/ImageLayout
if the library doesn't support auto-downsampling of the image, you should do it by yourself, in order to use the best image for the current device (so that you won't get OOM).
for auto-sizing text , you might have some luch with the next post:
Auto-fit TextView for Android

Android bitmaps in xml leak memory?

Here are some newbie memory management observations to which I would like
hear an experienced opinion.
It seems that setting android:backgound="#drawable/xyz" in a xml
layout causes memory loss in my app. The respective activities keep
stacking up until I get an OOM error. This is especially true if I rotate
the device orientation.
However, if I load the same resource with setBackgoundResource(), and then clear the
callback and set the background reference to null, there is no leak whatsoever.
that is, first in onCreate()
mMainLayout.setBackgroundResource(R.drawable.background_general_android);
and then in onDestroy()
mMainLayout.getBackground().setCallback(null);
mMainLayout.setBackgroundDrawable(null);
Is this roughly correct, or am I missing something essential?
This would only happen if you keep a copy of the drawables in a static cache for instance. You might also be leaking your activities and setting the drawables to null simply hides the problem for a little longer. You should use a tool like MAT to inspect the content of your heap and figure out what's going on.

Text and Fonts with Canvas in Android using OpenGL

I'm using the code outlined in the following post:
Draw text in OpenGL ES
I thought I could use this technique in order to dynamically display text (say an FPS counter). I realised that calls to resources to get the drawable slows down this process quite a lot, and I didn't need a bitmap background, so I removed it.
The technique works, but after a while (~2000 frames) the whole phone locks up. I suspect there's some memory which is not being freed in this code but I don't know where. I tried offloading the Canvas, Paint and Bitmap object creations which worked (so they aren't created every single frame) but the same problem still occurs.
I suspect therefore, that the generated GL texture is to blame, but I'm unsure how to remove it, or if this is even the case.
Any help would be appreciated.
EDIT: As an alternative, can someone please point out an easy way to render text to the screen dynamically (e.g. should be able to render the # of frames since starting for example, continually being updated and increasing). All the ways I can think of are either extremely tedious (make individual quads for each digit, store the textures for 0-9 in memory, parse the number and render each digit onto each quad), cannot be updated in good time (overlay Views) or can't get the required positioning in the glSurfaceView.
CBFG - http://www.codehead.co.uk/cbfg
This really is exactly what I've been wanting. You build a bitmap file from a font file using CBFG which can then be loaded and displayed with only a few lines of code (after importing his packages). It's literally as easy as fnt.PrintAt(gl,"Hello world!", 50, 160); in onDraw and more importantly, it handles dynamic text really well. I strongly advise anyone who is the same situation to try this.
two things I can guess you'll want to try:
1) dont' recreate the number of your frs every frame, generate number 1 to 60 and always reuse those.
2) there is an issue I found when generating text for my textures is that the font loader code of android never frees the memory space so avoid loading the font all the time, do it once and store a reference to it
I just wrote an entire tutorial on creating exactly what you are looking for.
The idea is basically to use font files and then generate a font bitmap (or atlas) at run-time instead of using a tool like CBFG to generate it offline. The benefit of this is that you can ship a small font file instead of multiple large bitmaps with your app, and never have to sacrifice font quality by using scaling.
The tutorial includes full working source (that can be dropped into any project). If you are interested go have a look here.

Categories

Resources