Ashwin Khadgi
Ashwin Khadgi

Reputation: 322

Android GroundoverLay consumes lot of memory

I am working on Android Weather application where my requirement is to show animated forecast. We have a server from where I load forecast images as Bitmap using Glide and then create GoogleMap's GroundOveryayOption using the bitmap. I am using Runnable and Handler for animation.

Everything is working fine except the memory consumption and eventually I got "Out of memory exception"

In-order to smoothly run my forecast animation I have to load all the Bitmaps using Glide and create GroundOverlayOptions obj from Bitmap and store GroundOverlayOptions in HashMap as below.

    @Override
            public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition<? super Bitmap> transition) {
                mBitmapLoaded = true;

//the actual image is png and its size is in KBs but Bitmap size is in MBs
                Log.i("Weather", ""+ bitmap.getByteCount());

                GroundOverlayOptions overlayOptions = new GroundOverlayOptions()
                        .image(BitmapDescriptorFactory.fromBitmap(bitmap))
                        .positionFromBounds(getLatLngBounds(mBounds))
                        .visible(frameVisible);

    //groundOverlaysItemMap is a Hashmap to store GroundOverlayOptions where key is Time
                groundOverlaysItemMap.put(mTime, mMap.addGroundOverlay(overlayOptions));
            }

Any help is appreciated.

Upvotes: 1

Views: 736

Answers (1)

Andrii Omelchenko
Andrii Omelchenko

Reputation: 13343

Split your "large" image into "small" (e.g. 256x256 pixels) tiles (for example with MapTiler like in this video), save them into raw folder (or device storage) and use TileProvider like in that answer of Alex Vasilkov:

public class CustomMapTileProvider implements TileProvider {
    private static final int TILE_WIDTH = 256;
    private static final int TILE_HEIGHT = 256;
    private static final int BUFFER_SIZE = 16 * 1024;

    private AssetManager mAssets;

    public CustomMapTileProvider(AssetManager assets) {
        mAssets = assets;
    }

    @Override
    public Tile getTile(int x, int y, int zoom) {
        byte[] image = readTileImage(x, y, zoom);
        return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image);
    }

    private byte[] readTileImage(int x, int y, int zoom) {
        InputStream in = null;
        ByteArrayOutputStream buffer = null;

        try {
            in = mAssets.open(getTileFilename(x, y, zoom));
            buffer = new ByteArrayOutputStream();

            int nRead;
            byte[] data = new byte[BUFFER_SIZE];

            while ((nRead = in.read(data, 0, BUFFER_SIZE)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();

            return buffer.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        } finally {
            if (in != null) try { in.close(); } catch (Exception ignored) {}
            if (buffer != null) try { buffer.close(); } catch (Exception ignored) {}
        }
    }

    private String getTileFilename(int x, int y, int zoom) {
        return "map/" + zoom + '/' + x + '/' + y + ".png";
    }
}

Upvotes: 1

Related Questions