在Android中为Google Maps API v2瓦片提供程序缓存国家OSM地图

3
我希望将设备中缓存的OSM地图用作Google Maps API V2的瓷砖提供程序。我已经阅读了这个有用的问题,但我不知道如何缓存这些瓷砖。
我拥有我的国家的OSM文件,但我该如何获得一个包含所有PNG文件的有组织的文件夹?
如果在设备上缓存所有PNG文件过于沉重,是否有任何Android库可以直接从OSM PBF文件中获取文件?
请注意,我想继续使用谷歌地图API而不是替代方案。

你打算如何显示这些瓦片? - MaM
关于如何离线显示瓦片的问题,已经有很多类似的提问了。 - scai
1个回答

2

我不知道pbf库(如果可以请检查OSMDroid)。

无论如何,我成功地在运行时自己缓存了来自openstreetmap的png。这意味着我只缓存了一个区域内显示的瓦片,而不是所有瓦片(我进行了暴力下载,但不建议这样做)。

下面是“缓存”实时瓦片的代码。如果您想要提供应用程序一起使用的png,然后读取它们,您可以尝试将png放置在文件夹结构中,该结构的第一级为缩放级别(Z),然后放置两个其他级别用于行/纬度(y)和列/经度(x),并在此处放置文件,最好的情况是文件具有三个值:Z_Y_X.png

您必须编辑“getTile”方法以检查上述创建的文件夹结构中的PNG文件。

以下是我的“实时缓存”代码:

/*
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.jakewharton.disklrucache.DiskLruCache;

/**
 * Wrapper that provides a disk-based LRU cache for a TileProvider.
 *
 * @see DiskLruCache
 */
public class CachedTileProvider implements TileProvider {

    private static final String TAG = CachedTileProvider.class.getSimpleName();

    private static final String KEY_FORMAT = "%3$d_%2$d_%1$d_%4$s";

    // Index for cache entry streams
    private static final int INDEX_DATA = 0;
    private static final int INDEX_HEIGHT = 1;
    private static final int INDEX_WIDTH = 2;

    //TEST
    private static final double[] TILES_ORIGIN = {-20037508.34789244, 20037508.34789244};//TODO Duplicate from WMS PROVIDER, put as utils
    // Size of square world map in meters, using WebMerc projection.
    private static final double MAP_SIZE = 20037508.34789244 * 2;//TODO Duplicate from WMS PROVIDER, put as utils
    private static final double ORIGIN_SHIFT = Math.PI * 6378137d;
//TEST


    private final String mKeyTag;
    private final TileProvider mTileProvider;
    //private final DiskLruCache mCache;
    private DiskLruCache mCache;
    private Set<String> cachedStringsWMS = null;
    Context cont = null;

    /**
     * TileProvider that wraps another TileProvider and caches all Tiles in a DiskLruCache.
     * <p/>
     * <p>A {@link DiskLruCache} can be reused across multiple instances.
     * The keyTag is used to annotate entries for this TileProvider, it is recommended to use a unique
     * String for each instance to prevent collisions.
     * <p/>
     * <p>NOTE: The supplied {@link DiskLruCache} requires space for
     * 3 entries per cached object.
     *
     * @param keyTag       identifier used to identify tiles for this CachedTileProvider instance
     * @param tileProvider tiles from this TileProvider will be cached.
     * @param cache        the cache used to store tiles
     */
    public CachedTileProvider(String keyTag, TileProvider tileProvider, DiskLruCache cache, Context context) {
        mKeyTag = keyTag;
        mTileProvider = tileProvider;
        mCache = cache;
        cont = context;
    }

    public void setNewDiskCache(DiskLruCache cache) {
        mCache = cache;
    }

    /**
     * Load a tile.
     * If cached, the data for the tile is read from the underlying cache, otherwise the tile is
     * generated by the {@link com.google.android.gms.maps.model.TileProvider} and added to the
     * cache.
     *
     * @param x
     * @param y
     * @param zoom
     * @return
     */
    @Override
    public Tile getTile(int x, int y, int zoom) {
        final String key = CachedTileProvider.generateKey(x, y, zoom, mKeyTag);
        Tile tile = getCachedTile(key);
        if (tile == null) {
            // tile not cached, load from provider and then cache
            tile = mTileProvider.getTile(x, y, zoom);
            if (null != tile && cacheTile(key, tile)) {
                if (BuildConfig.DEBUG) Log.d(TAG, "Added tile to cache " + key);
            }
        }
        return tile;
    }

    /**
     * Load a tile from cache.
     * Returns null if there is no corresponding cache entry or it could not be loaded.
     *
     * @param key
     * @return
     */
    private Tile getCachedTile(String key) {
        try {
            DiskLruCache.Snapshot snapshot = mCache.get(key);
            if (snapshot == null) {
                // tile is not in cache
                return null;
            }

            final byte[] data = readStreamAsByteArray(snapshot.getInputStream(INDEX_DATA));
            final int height = readStreamAsInt(snapshot.getInputStream(INDEX_HEIGHT));
            final int width = readStreamAsInt(snapshot.getInputStream(INDEX_WIDTH));
            if (data != null) {
                if (BuildConfig.DEBUG)Log.d(TAG, "Cache hit for tile " + key);
                return new Tile(width, height, data);
            }

        } catch (IOException e) {
            // ignore error
            e.printStackTrace();
        } catch (IllegalStateException ise) {
            Log.e(TAG, "IllegalStateException thrown, maybe cache is closed: " + ise.getMessage(), ise);
        }
        return null;
    }

    private boolean cacheTile(String key, Tile tile) {
        try {
            DiskLruCache.Editor editor = mCache.edit(key);
            if (editor == null) {
                // editor is not available
                return false;
            }
            writeByteArrayToStream(tile.data, editor.newOutputStream(INDEX_DATA));
            writeIntToStream(tile.height, editor.newOutputStream(INDEX_HEIGHT));
            writeIntToStream(tile.width, editor.newOutputStream(INDEX_WIDTH));
            editor.commit();
            return true;
        } catch (IOException e) {
            // Tile could not be cached
            e.printStackTrace();
        } catch (IllegalStateException ise) {
            Log.e(TAG, "IllegalStateException thrown, maybe cache is closed: " + ise.getMessage(), ise);
        }
        return false;
    }       

    private static String generateKey(int x, int y, int zoom, String tag) {
        return String.format(KEY_FORMAT, x, y, zoom, tag);
    }

    private static void writeByteArrayToStream(byte[] data, OutputStream stream) throws IOException {
        try {
            stream.write(data);
        } finally {
            stream.close();
        }
    }

    private static void writeIntToStream(int data, OutputStream stream) throws IOException {
        DataOutputStream dos = new DataOutputStream(stream);
        try {
            dos.writeInt(data);
        } finally {
            try {
                dos.close();
            } finally {
                stream.close();
            }
        }
    }

    private static byte[] readStreamAsByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int read = 0;
        byte[] data = new byte[1024];
        try {
            while ((read = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, read);
            }
        } finally {
            inputStream.close();
        }
        return buffer.toByteArray();
    }

    private static int readStreamAsInt(InputStream inputStream) throws IOException {
        DataInputStream buffer = new DataInputStream(inputStream);
        try {
            return buffer.readInt();
        } finally {
            inputStream.close();
        }
    }
}

然后,您可以通过将Tile提供程序封装起来创建该实例:
CachedTileProvider cachedTileProvider = new CachedTileProvider("osm", TileProviderFactory.getOSMBackGroundTileProvider(layerInfo.get(i)), mContext);

在哪里

public static TileProvider getOSMBackGroundTileProvider() {
        TileProvider mOSMTileProvider = new UrlTileProvider(256, 256) {

                @Override
                public URL getTileUrl(int x, int y, int z) {
                    try {
                        String f = "http://a.tile.openstreetmap.org/%d/%d/%d.png";
                        return new URL(String.format(f, z, x, y));
                    } catch (MalformedURLException e) {
                        return null;
                    }
                }
            };

        return mOSMTileProvider;
    }

现在您需要探索和检查jakewharton的DiskLruCache库,但是有很多文档可供参考,如果需要的话最好开一个新问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接