-8

Possible Duplicate:
java.lang.OutOfMemoryError: bitmap size exceeds VM budget - Android

I'm currently developing an Android app that displays images downloaded from URLs and put them in a ListView. And when it's clicked, creates a new ImageView of the image clicked. When smaller images (7kb) are clicked, it runs fine. Even runs fine up to 200kb. But anything larger than that, I get an error "The application has stopped unexpectedly. Please try again.". Looking at LogCat, it seems the problem has to do with Android running out of memory. Is there a solution to this? Or is it just a matter of having to lower the resolution of my images down to the 200kb range? Surely the image size shouldn't matter much up to 1 or 2 megabytes? It may take a bit longer to load but don't see why it would throw an error.

Any help would be much appreciated!

Zoom.java

public class Zoom extends Activity {

    @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.gallery_zoom);

        String selection = getIntent().getExtras().getString("image");
        Toast.makeText(this, selection, Toast.LENGTH_LONG).show();

        new backgroundLoader().execute();
    }


    public class backgroundLoader extends AsyncTask<Void, Void, Void> {
        Bitmap bmp;

        @Override
        protected Void doInBackground(Void... params) {
            BitmapFactory.Options bmpOptions;
            bmpOptions = new BitmapFactory.Options();
            bmpOptions.inSampleSize = 1;
            bmp = LoadImage(getIntent().getExtras().getString("image"), bmpOptions);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            ImageView image = (ImageView) findViewById(R.id.imageZoom);
            image.setImageBitmap(bmp);
            super.onPostExecute(result);
        }

    }

    private Bitmap LoadImage(String URL, BitmapFactory.Options options) {
        Bitmap bitmap = null;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in, null, options);
            in.close();
        } catch (IOException e1) {
        }
        return bitmap;

    }

    private InputStream OpenHttpConnection(String strURL) throws IOException {
        InputStream inputStream = null;
        URL url = new URL(strURL);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        try {
            InputStream in = new BufferedInputStream(connection.getInputStream());
            return in;
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }
    }

}

LogCat Logs

08-13 07:35:01.798: E/dalvikvm-heap(1132): 48064000-byte external allocation too large for this process.
08-13 07:35:01.888: E/GraphicsJNI(1132): VM won't let us allocate 48064000 bytes
08-13 07:35:01.888: D/dalvikvm(1132): GC_FOR_MALLOC freed 1K, 54% free 2694K/5831K, external 2229K/3423K, paused 19ms
08-13 07:35:01.888: D/skia(1132): --- decoder->decode returned false
08-13 07:35:01.888: W/dalvikvm(1132): threadid=14: thread exiting with uncaught exception (group=0x40015560)
08-13 07:35:01.898: E/AndroidRuntime(1132): FATAL EXCEPTION: AsyncTask #1
08-13 07:35:01.898: E/AndroidRuntime(1132): java.lang.RuntimeException: An error occured while executing doInBackground()
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.lang.Thread.run(Thread.java:1019)
08-13 07:35:01.898: E/AndroidRuntime(1132): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom.LoadImage(Zoom.java:72)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom.access$0(Zoom.java:67)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom$backgroundLoader.doInBackground(Zoom.java:54)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom$backgroundLoader.doInBackground(Zoom.java:1)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
08-13 07:35:01.898: E/AndroidRuntime(1132):     ... 4 more
08-13 07:35:01.908: W/ActivityManager(61):   Force finishing activity com.example.example.mobile.application/.gallery.Zoom
Community
  • 1
  • 1
user1006896
  • 315
  • 1
  • 5
  • 8

3 Answers3

1

I'd recommend considering a more complex caching method to make sure you never reach the VM's memory limit. A brilliant place for resources is Android's own advance lessons site. The most critical part of the tutorial is to create an LRUCache which is bounded to be a percentage of the VM's memory limit.

http://developer.android.com/training/displaying-bitmaps/index.html

luuts
  • 652
  • 4
  • 12
1

First you have to know that your 200Kb is a compressed jpg format. Android stores the images in a bitmap non compressed format. Depending on the size of your photo it can add up to several megabytes per photo.

To try to minimize the problem you can take a look at the BitmapFacotry insamplesize method :

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize

It allows you to open an image but in a lower resolution (by powers of two).

Also try to agressively call :

mybitmap = null;
System.gc;
System.runFinalization;
System.gc;

Every time you can.

Yahel
  • 8,522
  • 2
  • 24
  • 32
1

Some thoughts

  1. Don't keep a reference to the bitmap within AsyncTask, use it properly by defining Bitmap as param, not Void. Study here.

  2. You may need to recycle bitmaps. See Android developer training here on how to handle bitmaps.

  3. Study memory analysis tool (MAT) here.

auselen
  • 27,577
  • 7
  • 73
  • 114