【问题标题】:Google Maps Android Api 2 - Mixed TileProvider / URLTileProvider for MapBox implementationGoogle Maps Android Api 2 - 用于 MapBox 实现的混合 TileProvider / URLTileProvider
【发布时间】:2013-05-22 08:36:42
【问题描述】:

我想用这个功能实现一个 TileProvider:

  • Map 要求Tile
  • TileProvider 检查上述Tile 是否可以离线使用
  • 如果是这样,TileProvider 会返回说Tile
  • 无论可用性如何,TileProvider 都会在线检查新磁贴并将其下载到外部存储中的Cache
  • TileProvider 为地图提供新的 Tile,然后地图更新它。

这是我当前的UrlTileProvider 实现:

public class MapBoxOnlineTileProvider extends UrlTileProvider {

    private static final String[] FORMATS;

    static {
        final String[] servers = new String[] { "a", "b", "c", "d" };
        final String[] formats = new String[servers.length];
        for (int i = 0; i < servers.length; i++) {
            formats[i] = String.format(
                    "%%s://%s.tiles.mapbox.com/v3/%%s/%%d/%%d/%%d.png",
                    servers[i]);
        }
        FORMATS = formats;
    }

    // ------------------------------------------------------------------------
    // Instance Variables
    // ------------------------------------------------------------------------

    private String mMapIdentifier;

    // ------------------------------------------------------------------------
    // Constructors
    // ------------------------------------------------------------------------



    public MapBoxOnlineTileProvider(final String mapIdentifier) {
        super(256, 256);
        this.mMapIdentifier = mapIdentifier;
    }

    // ------------------------------------------------------------------------
    // Public Methods
    // ------------------------------------------------------------------------

    public String getMapIdentifier() {
        return this.mMapIdentifier;
    }

    public void setMapIdentifier(final String anIdentifier) {
        this.mMapIdentifier = anIdentifier;
    }

    @Override
    public URL getTileUrl(final int x, final int y, final int z) {
        final String f = FORMATS[new Random().nextInt(FORMATS.length)];
        final String p = "http";
        try {
            return new URL(String.format(f, p, this.mMapIdentifier, z, x, y));
        } catch (final MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    }
}

但是,这只会将其缓存在内存中,因此如果用户关闭我的应用程序,它不会缓存它们,并且默认的 Google Maps 地图将在下载 Tiles 之前出现。

UrlTileProvidergetTile 实现为final,所以我无法覆盖它。 TileProvider 没有getTileURL 方法,并且UrlTileProvider 源代码不可供我重写我的解决方案。

我应该如何处理这个问题?有什么办法可以做我想做的事吗?为什么getTile 是最终的?我错过了什么吗?

【问题讨论】:

    标签: android caching google-maps-android-api-2 mapbox


    【解决方案1】:

    用包裹在第一类的第二类解决了这个问题。

    尽管我不喜欢包装器,但这是我能想到的最好的方法,我必须说它工作得很好。

    public class MapBoxMixedTileProvider implements TileProvider {
    
        private final MapBoxOnlineTileProvider provider;
        private final Context context;
    
        public MapBoxMixedTileProvider(final Context context, final String mapId) {
            provider = new MapBoxOnlineTileProvider(mapId);
            this.context = context;
        }
    
        @Override
        public Tile getTile(final int arg0, final int arg1, final int arg2) {
            final URL url = provider.getTileUrl(arg0, arg1, arg2);
            // Remove the "http://a." from the url, then replace all the '/' and '.'
            // with
            // '_', then replace the final "_png" with ".png", so openFileInput
            // doesn't cry a lot.
            final String finalUrl = (url.toString().substring(9)).replace('/', '_')
                    .replace('.', '_').replace("_png", ".png");
            System.out.println(finalUrl);
            boolean contained = false;
            for (final String file : context.fileList()) {
                if (file.contains(finalUrl)) {
                    contained = true;
                    break;
                }
            }
            try {
                if (contained) {
                    final FileInputStream fis = context.openFileInput(finalUrl);
                    return new Tile(256, 256, byteArrayFromInputStream(fis));
                } else {
                    final FileOutputStream fos = context.openFileOutput(finalUrl,
                            Context.MODE_PRIVATE);
                    final Tile t = provider.getTile(arg0, arg1, arg2);
                    fos.write(t.data);
                    fos.flush();
                    fos.close();
                    return t;
                }
            } catch (final IOException ex) {
                ex.printStackTrace();
                return null;
            }
        }
    
        private byte[] byteArrayFromInputStream(final FileInputStream is)
                throws IOException {
            final BufferedInputStream bis = new BufferedInputStream(is);
            final ArrayList<Integer> bytes = new ArrayList<Integer>();
            int current = 0;
            while ((current = bis.read()) != -1) {
                bytes.add(Integer.valueOf(current));
            }
            final byte[] bs = new byte[bytes.size()];
            for (int i = 0; i < bytes.size(); i++) {
                bs[i] = bytes.get(i).byteValue();
            }
            bis.close();
            is.close();
            return bs;
        }
    
    }
    

    这样,为了让TileProvider 工作,我只需要这样做:

    final MapBoxMixedTileProvider provider = new MapBoxMixedTileProvider(
                            this, MAPBOX_MAP_IDENTIFIER);
    //zIndex is set to -4 so Polyines and Polygons get shown OVER and not under the Overlay
    final TileOverlayOptions overlay = new TileOverlayOptions().tileProvider(provider).zIndex(-4);
    tileOverlay = mMap.addTileOverlay(overlay);
    

    我知道我的 byteArrayFromInputStream 效率极低。欢迎对我的代码进行任何升级。

    【讨论】:

    • 什么是 MapBoxOnlineTileProvider?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    相关资源
    最近更新 更多