在osmdroid中下载titleSource的地图碎片title文件是否缓存的以及缓存大小的问题:
1.针对osmdroid的title文件缓存规律如下,第一次请求之后,缓存保存一定日期之后删除。
具体代码参考如下:
public class MapTileDownloader extends MapTileModuleProviderBase
- private class TileLoader extends MapTileModuleProviderBase.TileLoader {
- @Override
- public Drawable loadTile(final MapTileRequestState aState) throws CantContinueException {
- if (mTileSource == null) {
- return null;
- }
- InputStream in = null;
- OutputStream out = null;
- final MapTile tile = aState.getMapTile();
- try {
- if (mNetworkAvailablityCheck != null
- && !mNetworkAvailablityCheck.getNetworkAvailable()) {
- if (DEBUGMODE) {
- logger.debug("Skipping " + getName() + " due to NetworkAvailabliltyCheck.");
- }
- return null;
- }
- final String tileURLString = mTileSource.getTileURLString(tile);
- if (DEBUGMODE) {
- logger.debug("Downloading Maptile from url: " + tileURLString);
- }
- if (TextUtils.isEmpty(tileURLString)) {
- return null;
- }
- final HttpClient client = new DefaultHttpClient();
- final HttpUriRequest head = new HttpGet(tileURLString);
- final HttpResponse response = client.execute(head);
- // Check to see if we got success
- final org.apache.http.StatusLine line = response.getStatusLine();
- if (line.getStatusCode() != 200) {
- logger.warn("Problem downloading MapTile: " + tile + " HTTP response: " + line);
- return null;
- }
- final HttpEntity entity = response.getEntity();
- if (entity == null) {
- logger.warn("No content downloading MapTile: " + tile);
- return null;
- }
- in = entity.getContent();
- final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
- out = new BufferedOutputStream(dataStream, StreamUtils.IO_BUFFER_SIZE);
- StreamUtils.copy(in, out);
- out.flush();
- final byte[] data = dataStream.toByteArray();
- final ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
- // Save the data to the filesystem cache
- if (mFilesystemCache != null) {
- mFilesystemCache.saveFile(mTileSource, tile, byteStream);
- byteStream.reset();
- }
- final Drawable result = mTileSource.getDrawable(byteStream);
- return result;
- } catch (final UnknownHostException e) {
- // no network connection so empty the queue
- logger.warn("UnknownHostException downloading MapTile: " + tile + " : " + e);
- throw new CantContinueException(e);
- } catch (final LowMemoryException e) {
- // low memory so empty the queue
- logger.warn("LowMemoryException downloading MapTile: " + tile + " : " + e);
- throw new CantContinueException(e);
- } catch (final FileNotFoundException e) {
- logger.warn("Tile not found: " + tile + " : " + e);
- } catch (final IOException e) {
- logger.warn("IOException downloading MapTile: " + tile + " : " + e);
- } catch (final Throwable e) {
- logger.error("Error downloading MapTile: " + tile, e);
- } finally {
- StreamUtils.closeStream(in);
- StreamUtils.closeStream(out);
- }
- return null;
- }
首先采用在第一次请求地图的碎片时候,通过httpclient下载相关的碎片,下载成功之后,mFilesystemCache 是一个文件系统缓存处理器,缓存访问过的 地图碎片信息。
文件系统缓存器IFilesystemCache的一个具体实现如下:
public class TileWriter implements IFilesystemCache, OpenStreetMapTileProviderConstants
- public class TileWriter implements IFilesystemCache, OpenStreetMapTileProviderConstants {
- // ===========================================================
- // Constants
- // ===========================================================
- private static final Logger logger = LoggerFactory.getLogger(TileWriter.class);
- // ===========================================================
- // Fields
- // ===========================================================
- /** amount of disk space used by tile cache **/
- private static long mUsedCacheSpace;
- // ===========================================================
- // Constructors
- // ===========================================================
- public TileWriter() {
- // do this in the background because it takes a long time
- final Thread t = new Thread() {
- @Override
- public void run() {
- mUsedCacheSpace = 0; // because it's static
- calculateDirectorySize(TILE_PATH_BASE);
- if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {
- cutCurrentCache();
- }
- if (DEBUGMODE) {
- logger.debug("Finished init thread");
- }
- }
- };
- t.setPriority(Thread.MIN_PRIORITY);
- t.start();
- }
- // ===========================================================
- // Getter & Setter
- // ===========================================================
- /**
- * Get the amount of disk space used by the tile cache. This will initially be zero since the
- * used space is calculated in the background.
- *
- * @return size in bytes
- */
- public static long getUsedCacheSpace() {
- return mUsedCacheSpace;
- }
- // ===========================================================
- // Methods from SuperClass/Interfaces
- // ===========================================================
- @Override
- public boolean saveFile(final ITileSource pTileSource, final MapTile pTile,
- final InputStream pStream) {
- final File file = new File(TILE_PATH_BASE, pTileSource.getTileRelativeFilenameString(pTile)
- + TILE_PATH_EXTENSION);
- final File parent = file.getParentFile();
- if (!parent.exists() && !createFolderAndCheckIfExists(parent)) {
- return false;
- }
- BufferedOutputStream outputStream = null;
- try {
- outputStream = new BufferedOutputStream(new FileOutputStream(file.getPath()),
- StreamUtils.IO_BUFFER_SIZE);
- final long length = StreamUtils.copy(pStream, outputStream);
- mUsedCacheSpace += length;
- if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {
- cutCurrentCache(); // TODO perhaps we should do this in the background
- }
- } catch (final IOException e) {
- return false;
- } finally {
- if (outputStream != null) {
- StreamUtils.closeStream(outputStream);
- }
- }
- return true;
- }
- // ===========================================================
- // Methods
- // ===========================================================
- private boolean createFolderAndCheckIfExists(final File pFile) {
- if (pFile.mkdirs()) {
- return true;
- }
- if (DEBUGMODE) {
- logger.debug("Failed to create " + pFile + " - wait and check again");
- }
- // if create failed, wait a bit in case another thread created it
- try {
- Thread.sleep(500);
- } catch (final InterruptedException ignore) {
- }
- // and then check again
- if (pFile.exists()) {
- if (DEBUGMODE) {
- logger.debug("Seems like another thread created " + pFile);
- }
- return true;
- } else {
- if (DEBUGMODE) {
- logger.debug("File still doesn't exist: " + pFile);
- }
- return false;
- }
- }
- private void calculateDirectorySize(final File pDirectory) {
- final File[] z = pDirectory.listFiles();
- if (z != null) {
- for (final File file : z) {
- if (file.isFile()) {
- mUsedCacheSpace += file.length();
- }
- if (file.isDirectory() && !isSymbolicDirectoryLink(pDirectory, file)) {
- calculateDirectorySize(file); // *** recurse ***
- }
- }
- }
- }
- /**
- * Checks to see if it appears that a directory is a symbolic link. It does this by comparing
- * the canonical path of the parent directory and the parent directory of the directory's
- * canonical path. If they are equal, then they come from the same true parent. If not, then
- * pDirectory is a symbolic link. If we get an exception, we err on the side of caution and
- * return "true" expecting the calculateDirectorySize to now skip further processing since
- * something went goofy.
- */
- private boolean isSymbolicDirectoryLink(final File pParentDirectory, final File pDirectory) {
- try {
- final String canonicalParentPath1 = pParentDirectory.getCanonicalPath();
- final String canonicalParentPath2 = pDirectory.getCanonicalFile().getParent();
- return !canonicalParentPath1.equals(canonicalParentPath2);
- } catch (final IOException e) {
- return true;
- } catch (final NoSuchElementException e) {
- // See: http://code.google.com/p/android/issues/detail?id=4961
- // See: http://code.google.com/p/android/issues/detail?id=5807
- return true;
- }
- }
- private List<File> getDirectoryFileList(final File aDirectory) {
- final List<File> files = new ArrayList<File>();
- final File[] z = aDirectory.listFiles();
- if (z != null) {
- for (final File file : z) {
- if (file.isFile()) {
- files.add(file);
- }
- if (file.isDirectory()) {
- files.addAll(getDirectoryFileList(file));
- }
- }
- }
- return files;
- }
- /**
- * If the cache size is greater than the max then trim it down to the trim level. This method is
- * synchronized so that only one thread can run it at a time.
- */
- private void cutCurrentCache() {
- synchronized (TILE_PATH_BASE) {
- if (mUsedCacheSpace > TILE_TRIM_CACHE_SIZE_BYTES) {
- logger.info("Trimming tile cache from " + mUsedCacheSpace + " to "
- + TILE_TRIM_CACHE_SIZE_BYTES);
- final List<File> z = getDirectoryFileList(TILE_PATH_BASE);
- // order list by files day created from old to new
- final File[] files = z.toArray(new File[0]);
- Arrays.sort(files, new Comparator<File>() {
- @Override
- public int compare(final File f1, final File f2) {
- return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
- }
- });
- for (final File file : files) {
- if (mUsedCacheSpace <= TILE_TRIM_CACHE_SIZE_BYTES) {
- break;
- }
- final long length = file.length();
- if (file.delete()) {
- mUsedCacheSpace -= length;
- }
- }
- logger.info("Finished trimming tile cache");
- }
- }
- }
- }
在TileWriter 文件缓存器创建的时候,
1.创建一个线程检查相关的文件大小
代码如下:
- public TileWriter() {
- // do this in the background because it takes a long time
- final Thread t = new Thread() {
- @Override
- public void run() {
- mUsedCacheSpace = 0; // because it's static
- calculateDirectorySize(TILE_PATH_BASE);
- if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {
- cutCurrentCache();
- }
- if (DEBUGMODE) {
- logger.debug("Finished init thread");
- }
- }
- };
- t.setPriority(Thread.MIN_PRIORITY);
- t.start();
- }
2.在缓存中保存文件缓存的过程如下:
- @Override
- public boolean saveFile(final ITileSource pTileSource, final MapTile pTile,
- final InputStream pStream) {
- final File file = new File(TILE_PATH_BASE, pTileSource.getTileRelativeFilenameString(pTile)
- + TILE_PATH_EXTENSION);
- final File parent = file.getParentFile();
- if (!parent.exists() && !createFolderAndCheckIfExists(parent)) {
- return false;
- }
- BufferedOutputStream outputStream = null;
- try {
- outputStream = new BufferedOutputStream(new FileOutputStream(file.getPath()),
- StreamUtils.IO_BUFFER_SIZE);
- final long length = StreamUtils.copy(pStream, outputStream);
- mUsedCacheSpace += length;
- if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {
- cutCurrentCache(); // TODO perhaps we should do this in the background
- }
- } catch (final IOException e) {
- return false;
- } finally {
- if (outputStream != null) {
- StreamUtils.closeStream(outputStream);
- }
- }
- return true;
- }
3.清理文件缓存的方法实现如下:
- /**
- * If the cache size is greater than the max then trim it down to the trim level. This method is
- * synchronized so that only one thread can run it at a time.
- */
- private void cutCurrentCache() {
- synchronized (TILE_PATH_BASE) {
- if (mUsedCacheSpace > TILE_TRIM_CACHE_SIZE_BYTES) {
- logger.info("Trimming tile cache from " + mUsedCacheSpace + " to "
- + TILE_TRIM_CACHE_SIZE_BYTES);
- final List<File> z = getDirectoryFileList(TILE_PATH_BASE);
- // order list by files day created from old to new
- final File[] files = z.toArray(new File[0]);
- Arrays.sort(files, new Comparator<File>() {
- @Override
- public int compare(final File f1, final File f2) {
- return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
- }
- });
- for (final File file : files) {
- if (mUsedCacheSpace <= TILE_TRIM_CACHE_SIZE_BYTES) {
- break;
- }
- final long length = file.length();
- if (file.delete()) {
- mUsedCacheSpace -= length;
- }
- }
- logger.info("Finished trimming tile cache");
- }
- }
- }
由上述代码可以看出:看出缓存大于最大值时候清理缓存
- /** 30 days */
- public static final long TILE_EXPIRY_TIME_MILLISECONDS = 1000L * 60 * 60 * 24 * 30;
- /** 600 Mb */
- public static final long TILE_MAX_CACHE_SIZE_BYTES = 600L * 1024 * 1024;
- /** 500 Mb */
- public static final long TILE_TRIM_CACHE_SIZE_BYTES = 500L * 1024 * 1024;
- if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {
- cutCurrentCache(); // TODO perhaps we should do this in the background
- }
原文:http://topmanopensource.iteye.com/blog/1664631