Country OSM map caching in android for google maps api v2 tile provider

I just want to use OSM maps cached in device as tile provider for google maps api v2. I've read this helpful question , but I don't know how to cache tiles.

I have my country osm file, but how can I get an organized folder with all png files?

If caching all png files in the device is too heavy, is there any library in android to get files from osm.pbf file?

Please note that I want to keep using googles map api, not a replacement.

+3


source to share


1 answer


I am not aware of the pbf libraries (you should check OSMDroid if possible). anyway, I've successfully cached myself at runtime, pngs coming from openstreetmap. This means that I have only cached the displayed fragments and not all of them in the scope (I did a rough load, but I do not recommend doing). I will leave below the code for "caching" the live fragments, if you want to provide the png along with the application and then read them, you can try to put the png in a folder structure that has the first level as the zoom level (Z), then add the other two level for rows / latitude (y) and columns / longitude (x) and then put the file, better if the file has three values: Z_Y_X.png

You need to edit the getTile method to check the PNG file in the folder structure created above.

Here's my code for "live caching" instead

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

      

Then you instantiate this file by completing the Tile providers:



CachedTileProvider cachedTileProvider = new CachedTileProvider("osm", TileProviderFactory.getOSMBackGroundTileProvider(layerInfo.get(i)), mContext);

      

Where

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;
    }

      

Now you need to examine and check the DiskLruCache library from jakewharton, but there is a lot of documentation for that, it would be better to open another question if needed.

+1


source







All Articles