我想使用TileProvider
最新的Android Maps API(v2)的新功能在上覆盖一些自定义图块GoogleMap
。但是,由于我的用户很多时候都无法上网,因此我希望将图块保存在设备上的zipfile / folder结构中。我将使用Maptiler
和来生成我的图块geotiffs
。我的问题是:
- 将磁贴存储在设备上的最佳方法是什么?
- 如何创建返回本地图块的TileProvider?
我想使用TileProvider
最新的Android Maps API(v2)的新功能在上覆盖一些自定义图块GoogleMap
。但是,由于我的用户很多时候都无法上网,因此我希望将图块保存在设备上的zipfile / folder结构中。我将使用Maptiler
和来生成我的图块geotiffs
。我的问题是:
Answers:
您可以将图块放入资源文件夹(如果应用程序大小可接受),也可以在首次启动时将其全部下载,然后将其放入设备存储设备(SD卡)中。
您可以像这样实现TileProvider:
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";
}
}
现在,您可以将其与您的GoogleMap实例一起使用:
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);
}
在我的情况下,我还遇到了由MapTiler生成的图块的y坐标问题,但是我通过将此方法添加到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;
}
然后从getTile()方法调用它,如下所示:
@Override
public Tile getTile(int x, int y, int zoom) {
y = fixYCoordinate(y, zoom);
...
}
[更新]
如果您知道自定义地图的exac区域,则应NO_TILE
从getTile(...)
方法中返回缺少的图块。
这是我的方法:
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);
}
在新API(v2)中添加自定义tileproviders的可能性很大,但是您提到用户大多处于脱机状态。如果用户在首次启动应用程序时处于脱机状态,则您将无法使用新的API,因为新API要求用户处于在线状态(看来至少要建立一次缓存),否则它将仅显示黑屏。
编辑2 / 22-14:我最近又遇到了同样的问题-为必须脱机工作的应用程序定制了磁贴。通过在客户端必须下载某些内容的初始视图中添加不可见的(w / h 0/0)mapview来解决该问题。这似乎可行,以后我可以在离线模式下使用mapview。