Tileprovider Using Local Tiles

TileProvider using local tiles

  1. You can put tiles into assets folder (if it is acceptable for the app size) or download them all on first start and put them into device storage (SD card).

  2. You can implement TileProvider like this:


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";
}
}

And now you can use it with your GoogleMap instance:

private void setUpMap() {
mMap.setMapType(GoogleMap.MAP_TYPE_NONE);

mMap.addTileOverlay(new TileOverlayOptions().tileProvider(new CustomMapTileProvider(getResources().getAssets())));

CameraUpdate upd = CameraUpdateFactory.newLatLngZoom(new LatLng(LAT, LON), ZOOM);
mMap.moveCamera(upd);
}

In my case I also had a problem with y coordinate of tiles generated by MapTiler, but I managed it by adding this method into CustomMapTileProvider:

/**
* Fixing tile's y index (reversing order)
*/
private int fixYCoordinate(int y, int zoom) {
int size = 1 << zoom; // size = 2^zoom
return size - 1 - y;
}

and callig it from getTile() method like this:

@Override
public Tile getTile(int x, int y, int zoom) {
y = fixYCoordinate(y, zoom);
...
}

[Upd]

If you know exac area of your custom map, you should return NO_TILE for missing tiles from getTile(...) method.

This is how I did it:

private static final SparseArray<Rect> TILE_ZOOMS = new SparseArray<Rect>() {{
put(8, new Rect(135, 180, 135, 181 ));
put(9, new Rect(270, 361, 271, 363 ));
put(10, new Rect(541, 723, 543, 726 ));
put(11, new Rect(1082, 1447, 1086, 1452));
put(12, new Rect(2165, 2894, 2172, 2905));
put(13, new Rect(4330, 5789, 4345, 5810));
put(14, new Rect(8661, 11578, 8691, 11621));
}};

@Override
public Tile getTile(int x, int y, int zoom) {
y = fixYCoordinate(y, zoom);

if (hasTile(x, y, zoom)) {
byte[] image = readTileImage(x, y, zoom);
return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image);
} else {
return NO_TILE;
}
}

private boolean hasTile(int x, int y, int zoom) {
Rect b = TILE_ZOOMS.get(zoom);
return b == null ? false : (b.left <= x && x <= b.right && b.top <= y && y <= b.bottom);
}

Creating a custom map with TileOverlay

I was able to figure out my problem.

The code was beginning to request the tiles from the map folder by counting zoom 1 as zoom 2, and since I had no tiles in the zoom folder 2 it did not display them.

The code works perfectly.

Influence the Tile size in Android Maps TileProvider?

The size of the tile specified in the constructor is the size of (every) bitmap tile you are supplying to the map. This allows you to provide tiles at different densities for different screens if you have such resources.
It will not change the size of the image that is drawn on the map. The physical size of a map tile is defined by the zoom level, where a zoom level of 0 is a single tile covering the entire world, 1 is 2x2 tiles, etc. This is part of an open web map standard for map tiles, not defined by Google.

API docs:
https://developers.google.com/maps/documentation/android/tileoverlay

Ref:
http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/



Related Topics



Leave a reply



Submit