13

I developed an application that uses lots of images on Android.

There are lots of images present in drawable folder say more then 100, I am developing application for animation of images. I used imageview to show GIF images. I have used the concept of Split gif images into multiple PNG format images and then use it.

Each time the user enters to the app, I can see the memory growing more and more until user gets the java.lang.OutOfMemoryError.

So what is the best/correct way to handle many images?

Below is my code:

dog_animation.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/DogView"
android:orientation="vertical" >

<ImageView
    android:id="@+id/dog_animation"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="0.19" />

dog_animation.xml (Drawable folder)

<?xml version="1.0" encoding="utf-8"?>

<item
    android:drawable="@drawable/image"
    android:duration="50"/>
<item
    android:drawable="@drawable/image1"
    android:duration="50"/>
<item
    android:drawable="@drawable/image2"
    android:duration="50"/>
<item
    android:drawable="@drawable/image3"
    android:duration="50"/>
<item
    android:drawable="@drawable/image4"
    android:duration="50"/>
<item
    android:drawable="@drawable/image5"
    android:duration="50"/>
<item
    android:drawable="@drawable/image6"
    android:duration="50"/>
<item
    android:drawable="@drawable/image7"
    android:duration="50"/>
<item
    android:drawable="@drawable/image8"
    android:duration="50"/>
<item
    android:drawable="@drawable/image9"
    android:duration="50"/>
<item
    android:drawable="@drawable/image10"
    android:duration="50"/>
<item
    android:drawable="@drawable/image11"
    android:duration="50"/>
<item
    android:drawable="@drawable/image12"
    android:duration="50"/>
<item
    android:drawable="@drawable/image13"
    android:duration="50"/>
<item
    android:drawable="@drawable/image14"
    android:duration="50"/>
<item
    android:drawable="@drawable/image15"
    android:duration="50"/>
<item
    android:drawable="@drawable/image16"
    android:duration="50"/>
<item
    android:drawable="@drawable/image17"
    android:duration="50"/>
<item
    android:drawable="@drawable/image18"
    android:duration="50"/>
<item
    android:drawable="@drawable/image19"
    android:duration="50"/>
<item
    android:drawable="@drawable/image20"
    android:duration="50"/>
<item
    android:drawable="@drawable/image21"
    android:duration="50"/>
<item
    android:drawable="@drawable/image22"
    android:duration="50"/>
<item
    android:drawable="@drawable/image23"
    android:duration="50"/>
<item
    android:drawable="@drawable/image24"
    android:duration="50"/>
<item
    android:drawable="@drawable/image25"
    android:duration="50"/>
<item
    android:drawable="@drawable/image26"
    android:duration="50"/>
<item
    android:drawable="@drawable/image27"
    android:duration="50"/>
<item
    android:drawable="@drawable/image28"
    android:duration="50"/>
<item
    android:drawable="@drawable/image29"
    android:duration="50"/>
<item
    android:drawable="@drawable/image30"
    android:duration="50"/>
<item
    android:drawable="@drawable/image31"
    android:duration="50"/>
<item
    android:drawable="@drawable/image32"
    android:duration="50"/>
<item
    android:drawable="@drawable/image33"
    android:duration="50"/>
<item
    android:drawable="@drawable/image34"
    android:duration="50"/>
<item
    android:drawable="@drawable/image35"
    android:duration="50"/>
<item
    android:drawable="@drawable/image36"
    android:duration="50"/>
<item
    android:drawable="@drawable/image37"
    android:duration="50"/>
<item
    android:drawable="@drawable/image38"
    android:duration="50"/>
<item
    android:drawable="@drawable/image39"
    android:duration="50"/>
<item
    android:drawable="@drawable/image40"
    android:duration="50"/>
<item
    android:drawable="@drawable/image41"
    android:duration="50"/>
<item
    android:drawable="@drawable/image42"
    android:duration="50"/>
<item
    android:drawable="@drawable/image43"
    android:duration="50"/>
<item
    android:drawable="@drawable/image44"
    android:duration="50"/>
<item
    android:drawable="@drawable/image45"
    android:duration="50"/>
<item
    android:drawable="@drawable/image46"
    android:duration="50"/>
<item
    android:drawable="@drawable/image47"
    android:duration="50"/>
<item
    android:drawable="@drawable/image48"
    android:duration="50"/>
<item
    android:drawable="@drawable/image49"
    android:duration="50"/>
<item
    android:drawable="@drawable/image50"
    android:duration="50"/>
<item
    android:drawable="@drawable/image51"
    android:duration="50"/>
<item
    android:drawable="@drawable/image52"
    android:duration="50"/>
<item
    android:drawable="@drawable/image53"
    android:duration="50"/>
<item
    android:drawable="@drawable/image54"
    android:duration="50"/>
<item
    android:drawable="@drawable/image55"
    android:duration="50"/>
<item
    android:drawable="@drawable/image56"
    android:duration="50"/>

Dog_Animation.java

public class Dog_Animation extends Activity {

Timer timer = new Timer();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.dog_animation);

    ImageView img = (ImageView) findViewById(R.id.dog_animation);
    img.setBackgroundResource(R.drawable.dog_animation);
    AnimationDrawable frameAnimation = (AnimationDrawable) img
            .getBackground();
    frameAnimation.start();

    timer.schedule(new TimerTask() {
        public void run() {
            Intent intent = new Intent(Dog_Animation.this,
                    Man_Animation.class);
            startActivity(intent);
        }
    }, 10000);
}
}

Now the problem is when i try to move from one activity to another which has same some other image to animate it's giving me error of java.lang.OutOfMemory.

I have tried with so many different solution like

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.DogView));
    System.gc();
}

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();
    }
}

and so other also but any solution is not working for me. Please help me to solve this issue. even i have referred http://androidactivity.wordpress.com/2011/09/24/solution-for-outofmemoryerror-bitmap-size-exceeds-vm-budget/ this link but not getting solve the issue.

user987339
  • 10,519
  • 8
  • 40
  • 45
InnocentKiller
  • 5,234
  • 7
  • 36
  • 84
  • The best way is to search here or on Google. There are MANY answers. – Simon Oct 24 '13 at 06:39
  • possible duplicate of [Strange out of memory issue while loading an image to a Bitmap object](http://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object) – Simon Oct 24 '13 at 06:40
  • Hey Simon, I have tried and searched a lot in google but not getting proper solution. That is the only reason i have asked this question/ – InnocentKiller Oct 24 '13 at 06:41
  • Looks like You have memory leak in the app. Have You tried to follow the tutorial here: http://android-developers.blogspot.kr/2011/03/memory-analysis-for-android.html (also, there's corresponding Google I/O talk available)? – sandrstar Oct 24 '13 at 08:11
  • Hey sandrstar, I have not tried the solution given by you, but surly i will try and let you know weather it is working or not in my case. Thanks for your suggestion. – InnocentKiller Oct 24 '13 at 08:37
  • Don't call System.gc(); manually it's a bad practice, if you want a complete answer why refer to this link: http://stackoverflow.com/a/2414120/2958420 – Luis Pena Apr 26 '14 at 21:59
  • Did you figure it out? I have the same problem...but I'm only using four images in my drawable...And I only have one activity. What does `android:largeHeap="true"` do? Thanks – Ruchir Baronia Nov 26 '15 at 21:54

6 Answers6

20

In your AndroidManifest.xml keep this inside application tag, add largeHeap like this:

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"/>
durron597
  • 31,968
  • 17
  • 99
  • 158
Ismaran Duwadi
  • 1,529
  • 12
  • 10
3

try stopping your animation at onPause(). there is a big chance its not getting GCED because of that. also optimize ur bitmaps using this site http://tinypng.org, if you don't need the alpha layer, set it to 24bit

hepizoj
  • 243
  • 4
  • 9
1

Replace:

img.setBackgroundResource(R.drawable.dog_animation);

By:

img.setImageBitmap(decodeSampleBitmapFromResource(R.drawable.dog_animation, width, height));
//dont forget to replace width and heigh by your imageview dimension

An add:

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

and

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

This is from: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Pumpkin
  • 319
  • 2
  • 3
  • 11
1

In the above answer there is a getResources() missing in

img.setImageBitmap(decodeSampleBitmapFromResource(R.drawable.dog_animation, width, height));

so it becomes

img.setImageBitmap(decodeSampleBitmapFromResource(getResources(), R.drawable.dog_animation, width, height));
0

Few days ago, I had the same issue and it generated a similar log. So this is how I went about solving the issue.

I learned that the pixel of an image being loaded in an ImageView in Android Studio mustn't exceed width 1440 and height 2560.

The most voted solution on stackoverflow asked is to add the following in our manifest file: android:hardwareAccelerated="false" , android:largeHeap="true"

just as show in this image As I implemented this, the error wasn't thrown, but this did not work for all devices, it rather only worked for my emulator.

So, to solve this dilema for my phone, I simply cropped the associated images to the limit pixel after checking the pixel of each image and discarded that was too large for cropping(resizing). Note: for a large number of images you can right a code that checks for the images that exceed the amount of pixel required.

this is the link to my issue on github.com (allenbangai)

Ryan M
  • 18,333
  • 31
  • 67
  • 74
-5
try {
    //Code here that cause OutOfMemoryError
} catch (Error ee) {
    ee.printStacktrace();
}
Arfan Mirza
  • 668
  • 1
  • 14
  • 24