OSMDroid从资产文件夹加载自定义离线贴图

我想知道是否有可能做这样的事情。 我知道需要修改一些现有的代码来解决这个问题,但是我想知道是否有人在哪里寻找方向以及如何去做。

我在地图上的特定区域放置了一些自定义图块作为OSM磁贴供应商的替代品,但需要将它们存储在/ assets /文件夹中。 有任何想法吗?

Solutions Collecting From Web of "OSMDroid从资产文件夹加载自定义离线贴图"

我使用下一个类来做到这一点。

import java.io.InputStream; import org.osmdroid.ResourceProxy.string; import org.osmdroid.tileprovider.util.StreamUtils; import android.content.res.AssetManager; import android.graphics.drawable.Drawable; public class AssetsTileSource extends CustomBitmapTileSourceBase { private final AssetManager mAssetManager; public AssetsTileSource(final AssetManager assetManager, final String aName, final string aResourceId, final int aZoomMinLevel, final int aZoomMaxLevel, final int aTileSizePixels, final String aImageFilenameEnding) { super(aName, aResourceId, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels, aImageFilenameEnding); mAssetManager = assetManager; } @Override public Drawable getDrawable(final String aFilePath) { InputStream inputStream = null; try { inputStream = mAssetManager.open(aFilePath); if (inputStream != null) { final Drawable drawable = getDrawable(inputStream); return drawable; } } catch (final Throwable e) { // Tile does not exist in assets folder. // Ignore silently } finally { if (inputStream != null) { StreamUtils.closeStream(inputStream); } } return null; } } 

MapTileFileAssetsProvider.java

 public class MapTileFileAssetsProvider extends MapTileModuleProviderBase { protected ITileSource mTileSource; public MapTileFileAssetsProvider(final ITileSource pTileSource) { super(OpenStreetMapTileProviderConstants.NUMBER_OF_TILE_FILESYSTEM_THREADS, OpenStreetMapTileProviderConstants.TILE_FILESYSTEM_MAXIMUM_QUEUE_SIZE); mTileSource = pTileSource; } @Override public boolean getUsesDataConnection() { return false; } @Override protected String getName() { return "Assets Folder Provider"; } @Override protected String getThreadGroupName() { return "assetsfolder"; } @Override protected Runnable getTileLoader() { return new TileLoader(); } @Override public int getMinimumZoomLevel() { return mTileSource != null ? mTileSource.getMinimumZoomLevel() : MAXIMUM_ZOOMLEVEL; } @Override public int getMaximumZoomLevel() { return mTileSource != null ? mTileSource.getMaximumZoomLevel() : MINIMUM_ZOOMLEVEL; } @Override public void setTileSource(final ITileSource pTileSource) { mTileSource = pTileSource; } private class TileLoader extends MapTileModuleProviderBase.TileLoader { @Override public Drawable loadTile(final MapTileRequestState pState) throws CantContinueException { if (mTileSource == null) { return null; } final MapTile pTile = pState.getMapTile(); String path = mTileSource.getTileRelativeFilenameString(pTile); Drawable drawable; try { drawable = mTileSource.getDrawable(path); } catch (final LowMemoryException e) { // low memory so empty the queue throw new CantContinueException(e); } return drawable; } } } 

 import java.io.File; import java.io.InputStream; import java.util.Random; import org.osmdroid.ResourceProxy; import org.osmdroid.ResourceProxy.string; import org.osmdroid.tileprovider.ExpirableBitmapDrawable; import org.osmdroid.tileprovider.MapTile; import org.osmdroid.tileprovider.constants.OpenStreetMapTileProviderConstants; import org.osmdroid.tileprovider.tilesource.ITileSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; public abstract class CustomBitmapTileSourceBase implements ITileSource, OpenStreetMapTileProviderConstants { private static final Logger logger = LoggerFactory.getLogger(CustomBitmapTileSourceBase.class); private static int globalOrdinal = 0; private final int mMinimumZoomLevel; private final int mMaximumZoomLevel; private final int mOrdinal; protected final String mName; protected final String mImageFilenameEnding; protected final Random random = new Random(); private final int mTileSizePixels; private final string mResourceId; public CustomBitmapTileSourceBase(final String aName, final string aResourceId, final int aZoomMinLevel, final int aZoomMaxLevel, final int aTileSizePixels, final String aImageFilenameEnding) { mResourceId = aResourceId; mOrdinal = globalOrdinal++; mName = aName; mMinimumZoomLevel = aZoomMinLevel; mMaximumZoomLevel = aZoomMaxLevel; mTileSizePixels = aTileSizePixels; mImageFilenameEnding = aImageFilenameEnding; } @Override public int ordinal() { return mOrdinal; } @Override public String name() { return mName; } public String pathBase() { return mName; } public String imageFilenameEnding() { return mImageFilenameEnding; } @Override public int getMinimumZoomLevel() { return mMinimumZoomLevel; } @Override public int getMaximumZoomLevel() { return mMaximumZoomLevel; } @Override public int getTileSizePixels() { return mTileSizePixels; } @Override public String localizedName(final ResourceProxy proxy) { return proxy.getString(mResourceId); } @Override public Drawable getDrawable(final String aFilePath) { try { // default implementation will load the file as a bitmap and create // a BitmapDrawable from it final Bitmap bitmap = BitmapFactory.decodeFile(aFilePath); if (bitmap != null) { return new ExpirableBitmapDrawable(bitmap); } else { // if we couldn't load it then it's invalid - delete it try { new File(aFilePath).delete(); } catch (final Throwable e) { logger.error("Error deleting invalid file: " + aFilePath, e); } } } catch (final OutOfMemoryError e) { logger.error("OutOfMemoryError loading bitmap: " + aFilePath); System.gc(); } return null; } @Override public String getTileRelativeFilenameString(final MapTile tile) { final StringBuilder sb = new StringBuilder(); sb.append(pathBase()); sb.append('/'); sb.append(tile.getX()); sb.append('_'); sb.append(tile.getY()); sb.append('_'); sb.append(tile.getZoomLevel()); sb.append(imageFilenameEnding()); return sb.toString(); } @Override public Drawable getDrawable(final InputStream aFileInputStream) { try { // default implementation will load the file as a bitmap and create // a BitmapDrawable from it final Bitmap bitmap = BitmapFactory.decodeStream(aFileInputStream); if (bitmap != null) { return new ExpirableBitmapDrawable(bitmap); } System.gc(); } catch (final OutOfMemoryError e) { logger.error("OutOfMemoryError loading bitmap"); System.gc(); //throw new LowMemoryException(e); } return null; } public final class LowMemoryException extends Exception { private static final long serialVersionUID = 146526524087765134L; public LowMemoryException(final String pDetailMessage) { super(pDetailMessage); } public LowMemoryException(final Throwable pThrowable) { super(pThrowable); } } } 

修改方法getTileRelativeFilenameString()获取你的瓷砖(我使用下一个格式:x_y_zoom.png)

例:

 mapView = new MapView(getApplicationContext(), 256); mapView.setClickable(true); mapView.setTag("Mapa"); mapView.setTileSource(TileSourceFactory.MAPNIK); mapView.setMultiTouchControls(true); mapView.setUseDataConnection(true); MapTileModuleProviderBase moduleProvider = new MapTileFileAssetsProvider(ASSETS_TILE_SOURCE); SimpleRegisterReceiver simpleReceiver = new SimpleRegisterReceiver(getApplicationContext()); MapTileProviderArray tileProviderArray = new MapTileProviderArray(ASSETS_TILE_SOURCE, simpleReceiver, new MapTileModuleProviderBase[] { moduleProvider }); TilesOverlay tilesOverlay = new TilesOverlay(tileProviderArray, getApplicationContext()); mapView.getOverlays().add(tilesOverlay); 

而不是直接从资产中读取我复制/部署地图(压缩的osmdroid地图瓷砖目录结构格式)到osmdroid maptiles目录,然后声明3瓷砖供应商,存档,caching和在线提供商。

 public class MapTileProviderAssets extends MapTileProviderArray implements IMapTileProviderCallback { private static final String LOG_TAG = "MapTileProviderAssets"; private static final String ASSETS_MAP_DIRECTORY = "map"; private static final String SDCARD_PATH = Environment.getExternalStorageDirectory().getPath(); private static final String OSMDROID_MAP_FILE_SOURCE_DIRECTORY = "osmdroid"; private static final String OSMDROID_MAP_FILE_SOURCE_DIRECTORY_PATH = SDCARD_PATH + "/" + OSMDROID_MAP_FILE_SOURCE_DIRECTORY; public MapTileProviderAssets(final Context pContext) { this(pContext, TileSourceFactory.DEFAULT_TILE_SOURCE); } public MapTileProviderAssets(final Context pContext, final ITileSource pTileSource) { this(pContext, new SimpleRegisterReceiver(pContext), new NetworkAvailabliltyCheck(pContext), pTileSource); } public MapTileProviderAssets(final Context pContext, final IRegisterReceiver pRegisterReceiver, final INetworkAvailablityCheck aNetworkAvailablityCheck, final ITileSource pTileSource) { super(pTileSource, pRegisterReceiver); final TileWriter tileWriter = new TileWriter(); // copy assets delivered in apk into osmdroid map source dir // load zip archive first, then cache, then online final List<String> zipArchivesRelativePathInAssets = listArchives(pContext.getAssets(), ASSETS_MAP_DIRECTORY); for (final String zipFileRelativePathInAssets : zipArchivesRelativePathInAssets) { final String copiedFilePath = copyAssetFile( pContext.getAssets(), zipFileRelativePathInAssets, OSMDROID_MAP_FILE_SOURCE_DIRECTORY); Log.d(LOG_TAG, String.format( "Archive zip file copied into map source directory %s", copiedFilePath)); } // list zip files in map archive directory final Set<String> setZipFileArchivesPath = new HashSet<String>(); FileTools.listFiles(setZipFileArchivesPath, new File( OSMDROID_MAP_FILE_SOURCE_DIRECTORY_PATH), ".zip", true); final Set<IArchiveFile> setZipFileArchives = new HashSet<IArchiveFile>(); for (final String zipFileArchivesPath : setZipFileArchivesPath) { final File zipfile = new File(zipFileArchivesPath); final IArchiveFile archiveFile = ArchiveFileFactory.getArchiveFile(zipfile); if (archiveFile != null) { setZipFileArchives.add(archiveFile); } setZipFileArchives.add(archiveFile); Log.d(LOG_TAG, String.format( "Archive zip file %s added to map source ", zipFileArchivesPath)); } final MapTileFileArchiveProvider archiveProvider; Log.d(LOG_TAG, String.format( "%s archive zip files will be used as source", setZipFileArchives.size())); if (setZipFileArchives.size() > 0) { final IArchiveFile[] pArchives = setZipFileArchives.toArray(new IArchiveFile[setZipFileArchives.size()]); archiveProvider = new MapTileFileArchiveProvider( pRegisterReceiver, pTileSource, pArchives); } else { archiveProvider = new MapTileFileArchiveProvider( pRegisterReceiver, pTileSource); } mTileProviderList.add(archiveProvider); // cache final MapTileFilesystemProvider fileSystemProvider = new MapTileFilesystemProvider(pRegisterReceiver, pTileSource); mTileProviderList.add(fileSystemProvider); // online tiles final MapTileDownloader downloaderProvider = new MapTileDownloader(pTileSource, tileWriter, aNetworkAvailablityCheck); mTileProviderList.add(downloaderProvider); } public static List<String> listArchives(final AssetManager assetManager, final String subDirectory) { final List<String> listArchives = new ArrayList<String>(); try { final String[] lstFiles = assetManager.list(subDirectory); if (lstFiles != null && lstFiles.length > 0) { for (final String file : lstFiles) { if (isZip(file)) { listArchives.add(subDirectory + "/" + file); } // filter files (xxxxx.xxx format) and parse only directories, // with out this all files are parsed and // the process is VERY slow // WARNNING: we could have directories with dot for versioning else if (isDirectory(file)) {// (file.lastIndexOf(".") != (file.length() - 4)) { listArchives(assetManager, subDirectory + "/" + file); } } } } catch (final IOException e) { Log.w(LOG_TAG, String.format("List error: can't list %s, exception %s", subDirectory, Log.getStackTraceString(e))); } catch (final Exception e) { Log.w(LOG_TAG, String.format("List error: can't list %s, exception %s", subDirectory, Log.getStackTraceString(e))); } return listArchives; } private static boolean isZip(final String file) { return file.endsWith(".zip"); } private static boolean isDirectory(final String file) { return file.lastIndexOf(".") != (file.length() - 4); } private static String copyAssetFile(final AssetManager assetManager, final String assetRelativePath, final String destinationDirectoryOnSdcard) { InputStream in = null; OutputStream out = null; final String newfilePath = SDCARD_PATH + "/" + destinationDirectoryOnSdcard + "/" + assetRelativePath; final File newFile = new File(newfilePath); // copy file only if it doesn't exist yet if (!newFile.exists()) { Log.d(LOG_TAG, String.format( "Copy %s map archive in assets into %s", assetRelativePath, newfilePath)); try { final File directory = newFile.getParentFile(); if (!directory.exists()) { if (directory.mkdirs()) { // Log.d(LOG_TAG, "Directory created: " + directory.getAbsolutePath()); } } in = assetManager.open(assetRelativePath); out = new FileOutputStream(newfilePath); copyFile(in, out); in.close(); in = null; out.flush(); out.close(); out = null; } catch (final Exception e) { Log.e(LOG_TAG, "Exception during copyAssetFile: " + Log.getStackTraceString(e)); } } return newfilePath; } private static void copyFile(final InputStream in, final OutputStream out) throws IOException { final byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } } }