how to solve OutOfMemoryError in android? - android

I have prepared no.of drawable animations.when application launch first animation will be start.i have two buttons(next and previous) with same activity.when i click on next button i got exception like,
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
My code is,
For getting drawable animations from drawable,
private void getAnimationForLetters(int mAnim) {
// TODO Auto-generated method stub
String anim = "capital_anim_" + new Integer(mAnim).toString();
final int resID = getApplicationContext().getResources().getIdentifier(
anim, "drawable", "my-package-name");
mImgLetter.clearAnimation();
mImgLetter.setBackgroundResource(resID);
mImgLetter.post(new Runnable() {
public void run() {
loadingAnimation = (AnimationDrawable) mImgLetter
.getBackground();
loadingAnimation.start();
}
});
}
my next button code is,
case R.id.btnNext_:
unbindDrawables(findViewById(R.id.imgLetter));
mLetterNum=mLetterNum+1;
getAnimationForLetters(mLetterNum);
my undind drawable method code is,
private void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
finally i got exception java.lang.OutOfMemoryError: bitmap size exceeds VM budget
It is showing exception here mImgLetter.setBackgroundResource(resID);
Please help me.
I have added following code to clear,
loadingAnimation.stop();
for (int i = 0; i < loadingAnimation.getNumberOfFrames(); ++i){
Drawable frame = loadingAnimation.getFrame(i);
if (frame instanceof BitmapDrawable) {
((BitmapDrawable)frame).getBitmap().recycle();
}
frame.setCallback(null);
}
loadingAnimation.setCallback(null);
It is working fine for only next or previous.First time click on next animation move to second animation,second time if i click on previous button i got exception like,
Canvas: trying to use a recycled bitmap android.graphics.Bitmap
please help me.

exactly - the system knows when to collect garbage, so calling that doesn't help in the least.
You have to really really manage your apps memory. 290x330 may not seem like much, but if you're using full RGBA that's 4 bytes per pixel and your image turns into 380K. If you have several of these you're going to run out of memory. Most Android devices are not like PCs - they have rather limited memory. Some have only 16M or 24M to run everything, including the OS and any other apps the user might be running concurrently.
You might try wrapping your routine to load resources with try/catch
While( ! success ) {
try {
// load resources
} catch (OutOfMemoryError E) {
// do something to use less memory and try again
}
}

It may happen if you use high resolution images for mobiles with less resolution and memory. Make use Drawable-hdpi, Drawable-mdpi, Drawable-ldpi folders and place your images with suitable resolution.
FYI.. mostly you may also see this error in emulator when heapSize is too less. Try to increase heap size using AVD manager
This link might help you
Supporting multiple screen resolutions

Look at the below link the out of memory has been discussed in detail.
Android Out of memory issue
For me Thomas's solution has worked in past.
Hope it helps.

you can use this to free memory:
system.gc();

Related

is really image view set null ?

My problem is when i remove images from image View it remove image but when i monitor memory from android studio motorize tool it increasing memory
i am using Garbage collector .but its not good practice .
help me out with different solution.
private void cleanImages() {
img1.setImageDrawable(null);
}
public void clickClean4(View view) {
cleanImages();
System.runFinalization();
System.gc();
Runtime.getRuntime().gc();
}
You need to not only setImageDrawable(null); , but also recycle the bitmap.
You can do this by
if (!bitmapDrawable.getBitmap().isRecycled()) {
bitmapDrawable.getBitmap().recycle();
}
Hope it helps.

Free memory from AnimationDrawable

I'm using animationdrawables in many activities of my app. This is the code to inicializate them:
public void prepareVideo (int resourceBall, String animation, int width, int height ){
imgBall = (ImageView)findViewById(resourceBall);
imgBall.setVisibility(ImageView.VISIBLE);
String resourceNameAnimation = animation;
int id_res = getResources().getIdentifier(resourceNameAnimation, "drawable", getPackageName());
imgBall.setBackgroundResource(id_res);
LayoutParams latoutFrame = imgBall.getLayoutParams();
latoutFrame.width = width;
latoutFrame.height = height;
imgBall.setLayoutParams(latoutFrame);
frame = (AnimationDrawable) imgBall.getBackground();
}
Then i call:
imgBall.post(new StartAnimation());
that call a runnable:
class StartAnimation implements Runnable {
public void run() {
frame.start();
}
}
The problem is i use many animations that are the uses the same xml (frame by frame). I have to call this method in many activities with the same animation. Finally i get a outofmemoryerror. I'm trying to free memory between screens:
for (int i = 0; i < frame.getNumberOfFrames(); ++i){
Drawable frame_rescue = frame.getFrame(i);
if (frame_rescue instanceof BitmapDrawable) {
((BitmapDrawable)frame_rescue).getBitmap().recycle();
}
frame_rescue.setCallback(null);
The problem is that when i try to use a resourde again y get other error:
"Trying to use recycled bitmap"
Anyone know other way of free memory?
I had the same issue, the problem was the runnable.
Making an independent thread to each animation made animationDrawables persist after destroying the activity and clearing views and callbacks.
So starting animations without independent threads lets GC collect unused resources.

Canvas.drawBitmap() is intermittently slowed, causing white flashes

I am working on a live wallpaper with a scrolling background. I have two bitmap objects which I alternate between in order to keep the previously drawn pixels for the next frame. I draw a new line at the top of the canvas, then call drawBitmap to copy the rest of the pixels onto the canvas.
I am using a Runnable object to do the heavy lifting. It does all copying and calculations required and then locks the canvas, enters a synchronous block on the holder, and makes a single call to Canvas.drawBitmap(bitmap,rect,rect,paint). Occasionally there will be a white flash on the screen, which seems to correlate with high CPU activity. In using traceview, I found that the drawBitmap operation, specifically Canvas.native_drawBitmap(), is taking much longer than normal. Typically it completes in 2-4msec, but when I see a white flash, it can take anywhere from 10 to 100 msec.
private void draw() {
SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
prepareFrame();
try {
canvas = holder.lockCanvas();
synchronized (holder) {
if (canvas != null) {
drawFrame(canvas);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null)
holder.unlockCanvasAndPost(canvas);
}
afterDrawFrame();
handler.removeCallbacks(drawRunner);
if (visible) {
handler.post(drawRunner);
}
}
The draw() function is called in the run() of the Runnable.
private void prepareFrame() {
num++;
if (num%2 == 0) {
mainBmp = mainBmp1;
mainCan.setBitmap(mainBmp1);
mainCan.drawBitmap(mainBmp2, source, destination, null);
} else {
mainBmp = mainBmp2;
mainCan.setBitmap(mainBmp2);
mainCan.drawBitmap(mainBmp1, source, destination, null);
}
}
The prepareFrame() function is how I keep hold of the previous pixels I've drawn. The Rect called source is one row short of full screen sized at the bottom, where as destination is one row short at the top. The drawBitmap() calls in prepareFrame() are never longer than 2-4msec.
private void drawFrame(Canvas can) {
can.drawBitmap(mainBmp, source, destination,null);
}
This single operation is done on the canvas while holding the lock.
private void afterDrawFrame() {
ca.calcNextRow();
mainBmp.setPixels(ca.getRow(), 0, canWidth, 0, 0, canWidth, 1);
}
Then the next new row of pixels is drawn onto one of my bitmaps in memory.
I have tried using the various signatures of drawBitmap() but only found them slower on average and still resulting in the anomalous white flashes.
My overall speed is great. Without the intermittent flashes, it works really well. Does anyone have suggestions on how to eliminate the flashes?
It's kind of hard to know exactly what's going on here because you're not including the definition or use of some central variables like "mainCan" or "ca". A more complete source reference would be great.
But...
What's probably happening is that since drawFrame(canvas) is synchronized on holder, but
handler.post(drawRunner);
is not, there will be occurences where you are trying to draw mainBmp to the system canvas at the same time as you are writing to it in prepareFrame().
The best solution to this problem would probably be some kind of double buffering, where you do something like
1) Write to a temporary bitmap
2) Change the ref of that bitmap to the double buffer i.e. mainBmp = tempBitmap;
The main objective is to never do long writes to the variables you are using for system canvas rendering, just change the object reference.
Hope this helps.

Changing image consumes lot of time

Is there any way that I can increase the speed of setting the image? What I am trying to say is suppose I have some hundreds of images and each of those images can be changed automatically or by pressing forward/rewind buttons. (Think of the media player situation where you can forward or rewind as many files, same I am doing with images and some audio behind).
Now, if I continuously keep pressing RW/FW buttons, the layout appears to be black for some time or asks for force close or wait of the application.
Any one know how to increase this speed of reading the bitmap and setting it to the imageview?
Here is a part of my code,
private void playAudio() {
msg = new Message();
msg.obj = (filepath);
imageHandler.sendMessage(msg);
}
private Handler imageHandler = new Handler() {
public void handleMessage(Message msg) {
try {
path = (String) msg.obj;
imagePath = RaconTours.PATH + path;
imagenamearray = imagePath.split("/");
currentImagename = imagenamearray[8];
i++;
if (!imagePath.equalsIgnoreCase(staticpath)) {
isSeekBarChangedManually = false;
staticpath = imagePath;
Bitmap snoop = readBitmap(Uri.fromFile(new File(filepath)));
image.setImageBitmap(snoop);
image.setMaxZoom(4f);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Hope you get some idea with this code, this is just a small piece of the big cake.
I am not getting the method to solve this. I tried disabling the button also until some action is being performed but that is also of no use.
Any help, cheers
I think the only way to make this process "faster" is to load and cache the bitmaps in a buffer before you actually need them. When you need a bitmap, you check this forward-cache to see if it's already loaded. If it is, then it means it's already in memory -> you just need to set it for the proper ImageView (or whatever you use). If not, then you load it from the disk.
Of course, you need to know that which bitmaps you'll need most likely in the near future for this to work.
You can't really make disk I/O work any faster you see.

How to clear dynamically created view from memory?

I'm trying to clear some views from memory.
Here's the situation.
I have an Activity that I'll call it A and another B.
Now I press a button in Activity A that calls Activity B that creates a lot of views dynamically
After this, I press back button to return to Activity A
Repeat theses 2 steps a lot of times.
The result is, in DDMS, the number of objects and memory Allocated stills growing ( the number of objects is increased by 88 and Allocated by 0,002MB )
That means the views dont be removed from memory !
How do can I clear the views COMPLETELY from memory ?
Thx !
Update-
Here you go some new information
Basically, on my "real world" I have only one Activity that is created a lot of times. This occurs because I it have to communicate to a webservice and all the responses are created in that new instance of this Activity.
I tried to resolve this issue with the code below
#Override
protected void onDestroy() {
super.onDestroy();
nullViewDrawablesRecursive(mRootView);
mRootView = null;
System.gc();
}
and that is my nullViewDrawablesRecursive
private void nullViewDrawablesRecursive(View view) {
if (view != null) {
try {
ViewGroup viewGroup = (ViewGroup) view;
int childCount = viewGroup.getChildCount();
for (int index = 0; index < childCount; index++) {
View child = viewGroup.getChildAt(index);
nullViewDrawablesRecursive(child);
}
} catch (Exception e) {
}
nullViewDrawable(view);
}
}
And that is my nullViewDrawable
private void nullViewDrawable(View view) {
try {
view.setBackgroundDrawable(null);
} catch (Exception e) {
}
try {
ImageView imageView = (ImageView) view;
imageView.setImageDrawable(null);
imageView.setBackgroundDrawable(null);
} catch (Exception e) {
}
}
Basically I'm trying to remove all the views and childs from their parent (mRootView) before destroying the activity. It works pretty well, if I don't do this, the objects and memory usage increase more and more.
The point is, it's not perfect, apparently some type of views doesn't be destroyed. And I think I'm "reinventing the wheel", it seems to damn hard for a simple thing !
Again, thanks a lot for trying to help me!
Typically, you don't need to worry about clearing views from memory. You would let the virtual machine and Android framework handle this when it is necessary. However, you do need to be concerned with memory leaks. If your Activities are sharing/holding onto references to views, and they cannot be garbage collected, then that is a problem. You can start by reading about that here: http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
Its hard to provide some more specific advice without seeing you code though...
In onDestroy() set the views to null and call the garbage collector.
#Override
public void onDestroy() {
super.onDestroy();
myView = null;
System.gc();
}
This can help the garbage collector by calling System.gc() but it isn't guaranteed that the memory is cleared. However as long as you don't have a leak, there shouldn't be a problem.

Categories

Resources