Search code examples
androidbitmapmapsscale

GoogleMap/Custombitmap Tiles Load size exceeds VM budget java.lang.OutOfMemoryError:


How does Google scale the Images in Google Maps, Am trying to create an application where am using custom maps instead of Google maps. Everything is working well just this that I am not able to scale the images accordingly for phones with Dimension > 240 x 320, but for the phones with dimensions bigger than this crashes because I surpass the default heap size of an app in android and get java.lang.OutOfMemoryError: bitmap size exceeds VM budget. I just can't figure out how should I scale Images according to the Resolution of the phone.

This is what am doing :

1) First am calculating the Width and height of the phone :

Display display = getWindowManager().getDefaultDisplay();
            Constatnts.SCR_WD = display.getWidth();
            Constatnts.SCR_HT = display.getHeight();

2) I have set an onclicklistener for the zoomIn button which calls the zoomout function :

public void zoomOut() {
        if (isloading > 5)
            return;
        System.gc();

        if (zoomLevel < 12) {
            dc = true;
            sc = true;
            emptyBuffer();
            zoom = -1;
            stopload = true;
            bitmapArr1 = new Bitmap[tilesyno][tilesxno];
            for (int i = 0; i < bitmapArr.length; i++) {// row
                for (int j = 0; j < bitmapArr[i].length; j++) {// coloum
                    if (bitmapArr[i][j] != null) {
                        int tmpTilewd = bitmapArr[i][j].getWidth() / 2;
                        int tmpTileHt = bitmapArr[i][j].getHeight() / 2;
                        Bitmap b = ExtraFunctions.ScaleBitmap(bitmapArr[i][j],
                                tmpTilewd, tmpTileHt);
                        if (bitmapArr1 != null)
                            bitmapArr1[i][j] = b;
                    }
                }
            }

            lastPressed1 = System.currentTimeMillis();
            setCenterLatLon();
            zoomLevel++;
            if (!isStarted)
                tryLoadMap();
        }
    }


void tryLoadMap() {
        if (isStarted)
            return;
        isStarted = true;
        Thread th = new Thread() {
            public void run() {
                try {
                    Thread.sleep(System.currentTimeMillis() - lastPressed1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                loadLocalMap();
                if (showDirection)
                    DirectionPath(lat, lon);

                if (isSearchAvail)
                    SearchPath(lat, lon, tmpselected);

                isStarted = false;
            }
        };
        th.start();
    }

For scaling :

        public static Bitmap ScaleBitmap(Bitmap bitmapOrg,int newWidth,int newHeight) {
    if(bitmapOrg==null)
        return null;

    int width = bitmapOrg.getWidth();
    int height = bitmapOrg.getHeight();
    // calculate the scale - in this case = 0.4f
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;

    // createa matrix for the manipulation
    Matrix matrix = new Matrix();
    // resize the bit map
    matrix.postScale(scaleWidth, scaleHeight);
    // rotate the Bitmap
    //matrix.postRotate(45);

    // recreate the new Bitmap
    return Bitmap
            .createBitmap(bitmapOrg, 0, 0, width, height, matrix, true);
}

LOgcat :

08-30 17:09:30.342: E/dalvikvm-heap(440): 1451808-byte external allocation too large for this process.
08-30 17:09:30.382: E/GraphicsJNI(440): VM won't let us allocate 1451808 bytes
08-30 17:09:30.382: D/AndroidRuntime(440): Shutting down VM
08-30 17:09:30.401: W/dalvikvm(440): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
08-30 17:09:30.442: E/AndroidRuntime(440): FATAL EXCEPTION: main
08-30 17:09:30.442: E/AndroidRuntime(440): java.lang.IllegalStateException: Could not execute method of the activity
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.view.View$1.onClick(View.java:2072)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.view.View.performClick(View.java:2408)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.view.View$PerformClick.run(View.java:8816)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.os.Handler.handleCallback(Handler.java:587)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.os.Handler.dispatchMessage(Handler.java:92)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.os.Looper.loop(Looper.java:123)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.app.ActivityThread.main(ActivityThread.java:4627)
08-30 17:09:30.442: E/AndroidRuntime(440):  at java.lang.reflect.Method.invokeNative(Native Method)
08-30 17:09:30.442: E/AndroidRuntime(440):  at java.lang.reflect.Method.invoke(Method.java:521)
08-30 17:09:30.442: E/AndroidRuntime(440):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
08-30 17:09:30.442: E/AndroidRuntime(440):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
08-30 17:09:30.442: E/AndroidRuntime(440):  at dalvik.system.NativeStart.main(Native Method)
08-30 17:09:30.442: E/AndroidRuntime(440): Caused by: java.lang.reflect.InvocationTargetException
08-30 17:09:30.442: E/AndroidRuntime(440):  at com.Map.zoomIn(MapScreen.java:762)
08-30 17:09:30.442: E/AndroidRuntime(440):  at java.lang.reflect.Method.invokeNative(Native Method)
08-30 17:09:30.442: E/AndroidRuntime(440):  at java.lang.reflect.Method.invoke(Method.java:521)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.view.View$1.onClick(View.java:2067)
08-30 17:09:30.442: E/AndroidRuntime(440):  ... 11 more
08-30 17:09:30.442: E/AndroidRuntime(440): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.graphics.Bitmap.nativeCreate(Native Method)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
08-30 17:09:30.442: E/AndroidRuntime(440):  at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
08-30 17:09:30.442: E/AndroidRuntime(440):  at com.Map.ncore.XtraFunctions.ScaleBitmap(ExtraFunctions.java:32)
08-30 17:09:30.442: E/AndroidRuntime(440):  at com.Map.MapCanvas.zoomIn(MapCanvas.java:1018)
08-30 17:09:30.442: E/AndroidRuntime(440):  ... 15 more
08-30 17:14:30.522: I/Process(440): Sending signal. PID: 440 SIG: 9

Solution

  • Hmmm what is bitmapArr[i][j]? Are those decoded Bitmaps? if so then you're kind of missing the point. You should scale BEFORE reading them into bitmapArr. Otherwise you're keeping a copy of both the originals and the downsampled ones, saving nothing (and in fact using more memory). You should not read the image from disk (or wherever it is) before knowing what size you want to downscale to.