Android 使用本地瓷砖的瓷砖Provider

Android 使用本地瓷砖的瓷砖Provider,android,google-maps,android-maps-v2,Android,Google Maps,Android Maps V2,我想使用最新的Android Maps API(v2)的新的TileProvider功能在GoogleMap上覆盖一些自定义的Tile。然而,由于我的用户将不会有互联网的很多时间,我想保持瓷砖存储在zipfile/文件夹结构的设备上。我将使用Maptiler和geotiffs生成我的磁贴。我的问题是: 在设备上存储磁贴的最佳方式是什么 我如何创建一个返回本地瓷砖的瓷砖Provider 您可以将磁贴放入assets文件夹(如果应用程序大小可以接受),或者在第一次启动时将它们全部下载并放入设备存储(

我想使用最新的Android Maps API(v2)的新的
TileProvider
功能在
GoogleMap
上覆盖一些自定义的Tile。然而,由于我的用户将不会有互联网的很多时间,我想保持瓷砖存储在zipfile/文件夹结构的设备上。我将使用
Maptiler
geotiffs
生成我的磁贴。我的问题是:

  • 在设备上存储磁贴的最佳方式是什么
  • 我如何创建一个返回本地瓷砖的瓷砖Provider
  • 您可以将磁贴放入assets文件夹(如果应用程序大小可以接受),或者在第一次启动时将它们全部下载并放入设备存储(SD卡)

  • 您可以像这样实现TileProvider:

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

    现在,您可以将其用于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;
    }
    
    [Upd]

    如果您知道自定义地图的exac区域,您应该从
    getTile(…)
    方法返回
    NO_TILE
    以查找缺少的TILE

    我就是这样做的:

    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);
    }
    
    private static final SparseArray TILE\u ZOOMS=new SparseArray(){{
    put(8,新Rect(135180135181));
    put(9,新Rect(270,361,271,363));
    put(10,新Rect(541723543726));
    put(11,新Rect(1082144710861452));
    put(12,新Rect(2165289421722905));
    put(13,新Rect(43305789435810));
    put(14,新Rect(866111578869111621));
    }};
    @凌驾
    公共平铺getTile(整数x、整数y、整数缩放){
    y=固定坐标(y,缩放);
    if(黑斯泰尔(x,y,缩放)){
    字节[]图像=可读图像(x,y,缩放);
    返回图像==null?null:新瓷砖(瓷砖宽度、瓷砖高度、图像);
    }否则{
    不退地砖;
    }
    }
    私有布尔黑斯蒂尔(整数x,整数y,整数缩放){
    Rect b=TILE_ZOOMS.get(缩放);
    
    return b==null?false:(b.left在新API(v2)中添加自定义tileproviders的可能性很大,但是您提到您的用户大部分处于脱机状态。如果用户在首次启动应用程序时处于脱机状态,则无法使用新API,因为它要求用户处于联机状态(似乎至少有一次构建缓存)-否则,它将只显示一个黑屏

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

    请注意getTile(int,int,int)返回值的文档:用于此互动程序坐标的互动程序。如果您不希望为此互动程序坐标提供互动程序,请不返回任何互动程序。如果此时找不到互动程序,请返回null,并可能通过指数退避进行进一步请求。谢谢@JesperB,请参阅[Upd]回答部分谢谢-我有一个笨重的版本,是在API v2第一次出现时编写的,您的示例极大地提高了我的性能。FWIW,我的平铺集并没有形成一个完美的矩形,所以我通过检查输入流是否为空来检查平铺是否存在。Alex Vasilkov:in`CameraUpd=CameraUpdateFactory.newLatLngZoom(新LatLng(LAT,LON),ZOOM);`我必须通过哪个LAT,LAN?我可以问一下,人们是如何知道您在SparseArray中输入的值的?这四个值在Rect()中是什么?莫蒂,你从哪里得到这些信息?这是谷歌的官方意图吗?这将使得在没有互联网连接的情况下,无法使用gmap api v2离线显示本地存储的地图片。Tom@Tom恐怕他是对的。是的,这真的很重要。在这种情况下,你需要复制“ZoomTables.data”(初始化地图时将其从emulator中拉出来)到/data/data//files/有人能详细说明一下在飞机模式下首次启动时加载自定义地图磁贴的情况吗。我有自定义磁贴,需要显示它们,但getTile()第一次发射时不会被调用。我需要在飞机模式下第一次发射时显示自定义磁贴。同样,我想知道一件事,Google Map V2是否提供了下载/缓存磁贴的功能?()因为我在这个例子中感到困惑,这意味着如果他们提供了如何使用TileProvider类加载/使用磁贴,那么磁贴缓存/下载应该是可用的。我的实际需求是我需要根据用户的要求下载/缓存地图。我已经检查了OSMDROID库,但我想使用google map v2only@Rajan我是被同样的问题困扰着。似乎可以使用tileProvide进行缓存。您决定使用什么?@陀螺仪,您从哪里获得这些Tile?可以下载吗?
    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);
    }