TileProvider使用本地磁贴

我想使用最新Android Maps API(v2)的新TileProviderfunction来覆盖GoogleMap上的一些自定义贴图。 然而,因为我的用户很多时间都没有互联网,所以我想保持设备上的zip文件/文件夹结构中存储的磁贴。 我将使用带有geotiffs生成我的瓷砖。 我的问题是:

  1. 什么是将瓷砖存储在设备上的最佳方式?
  2. 我将如何去创build返回本地磁贴的TileProvider?
  1. 您可以将瓷砖放入资产文件夹(如果可接受的应用程序大小),或者在首次启动时将它们全部下载并放入设备存储(SD卡)中。

  2. 你可以像这样实现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生成的tile的y坐标的问题,但我通过将此方法添加到CustomMapTileProvider中来pipe理它:

 /** * 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); ... } 

[UPD]

如果您知道自定义贴图的颜色区域,则应该从getTile(...)方法返回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,因为它需要用户在线(至less一次构buildcaching),否则将只显示黑屏。

编辑2 / 22-14:我最近再次遇到同样的问题 – 有一个应用程序必须离线工作的自定义瓷砖。 通过在客户端必须下载一些内容的初始视图中添加一个不可见(w / h 0/0)的mapview来解决这个问题。 这似乎工作,并允许我以后在离线模式下使用mapview。