GIS的学习(十五)Osmdroid中TileSource几点研究

  在osmdroid中下载titleSource的地图碎片title文件是否缓存的以及缓存大小的问题:

1.针对osmdroid的title文件缓存规律如下,第一次请求之后,缓存保存一定日期之后删除。

具体代码参考如下:

public class MapTileDownloader extends MapTileModuleProviderBase

Java代码    收藏代码
  1. private class TileLoader extends MapTileModuleProviderBase.TileLoader {  
  2.   
  3.     @Override  
  4.     public Drawable loadTile(final MapTileRequestState aState) throws CantContinueException {  
  5.   
  6.         if (mTileSource == null) {  
  7.             return null;  
  8.         }  
  9.   
  10.         InputStream in = null;  
  11.         OutputStream out = null;  
  12.         final MapTile tile = aState.getMapTile();  
  13.   
  14.         try {  
  15.   
  16.             if (mNetworkAvailablityCheck != null  
  17.                     && !mNetworkAvailablityCheck.getNetworkAvailable()) {  
  18.                 if (DEBUGMODE) {  
  19.                     logger.debug("Skipping " + getName() + " due to NetworkAvailabliltyCheck.");  
  20.                 }  
  21.                 return null;  
  22.             }  
  23.   
  24.             final String tileURLString = mTileSource.getTileURLString(tile);  
  25.   
  26.             if (DEBUGMODE) {  
  27.                 logger.debug("Downloading Maptile from url: " + tileURLString);  
  28.             }  
  29.   
  30.             if (TextUtils.isEmpty(tileURLString)) {  
  31.                 return null;  
  32.             }  
  33.   
  34.             final HttpClient client = new DefaultHttpClient();  
  35.             final HttpUriRequest head = new HttpGet(tileURLString);  
  36.             final HttpResponse response = client.execute(head);  
  37.   
  38.             // Check to see if we got success  
  39.             final org.apache.http.StatusLine line = response.getStatusLine();  
  40.             if (line.getStatusCode() != 200) {  
  41.                 logger.warn("Problem downloading MapTile: " + tile + " HTTP response: " + line);  
  42.                 return null;  
  43.             }  
  44.   
  45.             final HttpEntity entity = response.getEntity();  
  46.             if (entity == null) {  
  47.                 logger.warn("No content downloading MapTile: " + tile);  
  48.                 return null;  
  49.             }  
  50.             in = entity.getContent();  
  51.   
  52.             final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();  
  53.             out = new BufferedOutputStream(dataStream, StreamUtils.IO_BUFFER_SIZE);  
  54.             StreamUtils.copy(in, out);  
  55.             out.flush();  
  56.             final byte[] data = dataStream.toByteArray();  
  57.             final ByteArrayInputStream byteStream = new ByteArrayInputStream(data);  
  58.   
  59.             // Save the data to the filesystem cache  
  60.             if (mFilesystemCache != null) {  
  61.                 mFilesystemCache.saveFile(mTileSource, tile, byteStream);  
  62.                 byteStream.reset();  
  63.             }  
  64.             final Drawable result = mTileSource.getDrawable(byteStream);  
  65.   
  66.             return result;  
  67.         } catch (final UnknownHostException e) {  
  68.             // no network connection so empty the queue  
  69.             logger.warn("UnknownHostException downloading MapTile: " + tile + " : " + e);  
  70.             throw new CantContinueException(e);  
  71.         } catch (final LowMemoryException e) {  
  72.             // low memory so empty the queue  
  73.             logger.warn("LowMemoryException downloading MapTile: " + tile + " : " + e);  
  74.             throw new CantContinueException(e);  
  75.         } catch (final FileNotFoundException e) {  
  76.             logger.warn("Tile not found: " + tile + " : " + e);  
  77.         } catch (final IOException e) {  
  78.             logger.warn("IOException downloading MapTile: " + tile + " : " + e);  
  79.         } catch (final Throwable e) {  
  80.             logger.error("Error downloading MapTile: " + tile, e);  
  81.         } finally {  
  82.             StreamUtils.closeStream(in);  
  83.             StreamUtils.closeStream(out);  
  84.         }  
  85.   
  86.         return null;  
  87.     }  

 

首先采用在第一次请求地图的碎片时候,通过httpclient下载相关的碎片,下载成功之后,mFilesystemCache 是一个文件系统缓存处理器,缓存访问过的 地图碎片信息。

 

 

文件系统缓存器IFilesystemCache的一个具体实现如下:

public class TileWriter implements IFilesystemCache, OpenStreetMapTileProviderConstants

Java代码    收藏代码
  1. public class TileWriter implements IFilesystemCache, OpenStreetMapTileProviderConstants {  
  2.   
  3.     // ===========================================================  
  4.     // Constants  
  5.     // ===========================================================  
  6.   
  7.     private static final Logger logger = LoggerFactory.getLogger(TileWriter.class);  
  8.   
  9.     // ===========================================================  
  10.     // Fields  
  11.     // ===========================================================  
  12.   
  13.     /** amount of disk space used by tile cache **/  
  14.     private static long mUsedCacheSpace;  
  15.   
  16.     // ===========================================================  
  17.     // Constructors  
  18.     // ===========================================================  
  19.   
  20.     public TileWriter() {  
  21.   
  22.         // do this in the background because it takes a long time  
  23.         final Thread t = new Thread() {  
  24.             @Override  
  25.             public void run() {  
  26.                 mUsedCacheSpace = 0// because it's static  
  27.                 calculateDirectorySize(TILE_PATH_BASE);  
  28.                 if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {  
  29.                     cutCurrentCache();  
  30.                 }  
  31.                 if (DEBUGMODE) {  
  32.                     logger.debug("Finished init thread");  
  33.                 }  
  34.             }  
  35.         };  
  36.         t.setPriority(Thread.MIN_PRIORITY);  
  37.         t.start();  
  38.     }  
  39.   
  40.     // ===========================================================  
  41.     // Getter & Setter  
  42.     // ===========================================================  
  43.   
  44.     /** 
  45.      * Get the amount of disk space used by the tile cache. This will initially be zero since the 
  46.      * used space is calculated in the background. 
  47.      * 
  48.      * @return size in bytes 
  49.      */  
  50.     public static long getUsedCacheSpace() {  
  51.         return mUsedCacheSpace;  
  52.     }  
  53.   
  54.     // ===========================================================  
  55.     // Methods from SuperClass/Interfaces  
  56.     // ===========================================================  
  57.   
  58.     @Override  
  59.     public boolean saveFile(final ITileSource pTileSource, final MapTile pTile,  
  60.             final InputStream pStream) {  
  61.   
  62.         final File file = new File(TILE_PATH_BASE, pTileSource.getTileRelativeFilenameString(pTile)  
  63.                 + TILE_PATH_EXTENSION);  
  64.   
  65.         final File parent = file.getParentFile();  
  66.         if (!parent.exists() && !createFolderAndCheckIfExists(parent)) {  
  67.             return false;  
  68.         }  
  69.   
  70.         BufferedOutputStream outputStream = null;  
  71.         try {  
  72.             outputStream = new BufferedOutputStream(new FileOutputStream(file.getPath()),  
  73.                     StreamUtils.IO_BUFFER_SIZE);  
  74.             final long length = StreamUtils.copy(pStream, outputStream);  
  75.   
  76.             mUsedCacheSpace += length;  
  77.             if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {  
  78.                 cutCurrentCache(); // TODO perhaps we should do this in the background  
  79.             }  
  80.         } catch (final IOException e) {  
  81.             return false;  
  82.         } finally {  
  83.             if (outputStream != null) {  
  84.                 StreamUtils.closeStream(outputStream);  
  85.             }  
  86.         }  
  87.         return true;  
  88.     }  
  89.   
  90.     // ===========================================================  
  91.     // Methods  
  92.     // ===========================================================  
  93.   
  94.     private boolean createFolderAndCheckIfExists(final File pFile) {  
  95.         if (pFile.mkdirs()) {  
  96.             return true;  
  97.         }  
  98.         if (DEBUGMODE) {  
  99.             logger.debug("Failed to create " + pFile + " - wait and check again");  
  100.         }  
  101.   
  102.         // if create failed, wait a bit in case another thread created it  
  103.         try {  
  104.             Thread.sleep(500);  
  105.         } catch (final InterruptedException ignore) {  
  106.         }  
  107.         // and then check again  
  108.         if (pFile.exists()) {  
  109.             if (DEBUGMODE) {  
  110.                 logger.debug("Seems like another thread created " + pFile);  
  111.             }  
  112.             return true;  
  113.         } else {  
  114.             if (DEBUGMODE) {  
  115.                 logger.debug("File still doesn't exist: " + pFile);  
  116.             }  
  117.             return false;  
  118.         }  
  119.     }  
  120.   
  121.     private void calculateDirectorySize(final File pDirectory) {  
  122.         final File[] z = pDirectory.listFiles();  
  123.         if (z != null) {  
  124.             for (final File file : z) {  
  125.                 if (file.isFile()) {  
  126.                     mUsedCacheSpace += file.length();  
  127.                 }  
  128.                 if (file.isDirectory() && !isSymbolicDirectoryLink(pDirectory, file)) {  
  129.                     calculateDirectorySize(file); // *** recurse ***  
  130.                 }  
  131.             }  
  132.         }  
  133.     }  
  134.   
  135.     /** 
  136.      * Checks to see if it appears that a directory is a symbolic link. It does this by comparing 
  137.      * the canonical path of the parent directory and the parent directory of the directory's 
  138.      * canonical path. If they are equal, then they come from the same true parent. If not, then 
  139.      * pDirectory is a symbolic link. If we get an exception, we err on the side of caution and 
  140.      * return "true" expecting the calculateDirectorySize to now skip further processing since 
  141.      * something went goofy. 
  142.      */  
  143.     private boolean isSymbolicDirectoryLink(final File pParentDirectory, final File pDirectory) {  
  144.         try {  
  145.             final String canonicalParentPath1 = pParentDirectory.getCanonicalPath();  
  146.             final String canonicalParentPath2 = pDirectory.getCanonicalFile().getParent();  
  147.             return !canonicalParentPath1.equals(canonicalParentPath2);  
  148.         } catch (final IOException e) {  
  149.             return true;  
  150.         } catch (final NoSuchElementException e) {  
  151.             // See: http://code.google.com/p/android/issues/detail?id=4961  
  152.             // See: http://code.google.com/p/android/issues/detail?id=5807  
  153.             return true;  
  154.         }  
  155.   
  156.     }  
  157.   
  158.     private List<File> getDirectoryFileList(final File aDirectory) {  
  159.         final List<File> files = new ArrayList<File>();  
  160.   
  161.         final File[] z = aDirectory.listFiles();  
  162.         if (z != null) {  
  163.             for (final File file : z) {  
  164.                 if (file.isFile()) {  
  165.                     files.add(file);  
  166.                 }  
  167.                 if (file.isDirectory()) {  
  168.                     files.addAll(getDirectoryFileList(file));  
  169.                 }  
  170.             }  
  171.         }  
  172.   
  173.         return files;  
  174.     }  
  175.   
  176.     /** 
  177.      * If the cache size is greater than the max then trim it down to the trim level. This method is 
  178.      * synchronized so that only one thread can run it at a time. 
  179.      */  
  180.     private void cutCurrentCache() {  
  181.   
  182.         synchronized (TILE_PATH_BASE) {  
  183.   
  184.             if (mUsedCacheSpace > TILE_TRIM_CACHE_SIZE_BYTES) {  
  185.   
  186.                 logger.info("Trimming tile cache from " + mUsedCacheSpace + " to "  
  187.                         + TILE_TRIM_CACHE_SIZE_BYTES);  
  188.   
  189.                 final List<File> z = getDirectoryFileList(TILE_PATH_BASE);  
  190.   
  191.                 // order list by files day created from old to new  
  192.                 final File[] files = z.toArray(new File[0]);  
  193.                 Arrays.sort(files, new Comparator<File>() {  
  194.                     @Override  
  195.                     public int compare(final File f1, final File f2) {  
  196.                         return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());  
  197.                     }  
  198.                 });  
  199.   
  200.                 for (final File file : files) {  
  201.                     if (mUsedCacheSpace <= TILE_TRIM_CACHE_SIZE_BYTES) {  
  202.                         break;  
  203.                     }  
  204.   
  205.                     final long length = file.length();  
  206.                     if (file.delete()) {  
  207.                         mUsedCacheSpace -= length;  
  208.                     }  
  209.                 }  
  210.   
  211.                 logger.info("Finished trimming tile cache");  
  212.             }  
  213.         }  
  214.     }  
  215.   
  216. }  

 

在TileWriter 文件缓存器创建的时候,

1.创建一个线程检查相关的文件大小

代码如下:

Java代码    收藏代码
  1. public TileWriter() {  
  2.   
  3.  // do this in the background because it takes a long time  
  4.  final Thread t = new Thread() {  
  5.   @Override  
  6.   public void run() {  
  7.    mUsedCacheSpace = 0// because it's static  
  8.    calculateDirectorySize(TILE_PATH_BASE);  
  9.    if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {  
  10.     cutCurrentCache();  
  11.    }  
  12.    if (DEBUGMODE) {  
  13.     logger.debug("Finished init thread");  
  14.    }  
  15.   }  
  16.  };  
  17.  t.setPriority(Thread.MIN_PRIORITY);  
  18.  t.start();  
  19. }  

 2.在缓存中保存文件缓存的过程如下:

Java代码    收藏代码
  1. @Override  
  2. public boolean saveFile(final ITileSource pTileSource, final MapTile pTile,  
  3.         final InputStream pStream) {  
  4.   
  5.     final File file = new File(TILE_PATH_BASE, pTileSource.getTileRelativeFilenameString(pTile)  
  6.             + TILE_PATH_EXTENSION);  
  7.   
  8.     final File parent = file.getParentFile();  
  9.     if (!parent.exists() && !createFolderAndCheckIfExists(parent)) {  
  10.         return false;  
  11.     }  
  12.   
  13.     BufferedOutputStream outputStream = null;  
  14.     try {  
  15.         outputStream = new BufferedOutputStream(new FileOutputStream(file.getPath()),  
  16.                 StreamUtils.IO_BUFFER_SIZE);  
  17.         final long length = StreamUtils.copy(pStream, outputStream);  
  18.   
  19.         mUsedCacheSpace += length;  
  20.         if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {  
  21.             cutCurrentCache(); // TODO perhaps we should do this in the background  
  22.         }  
  23.     } catch (final IOException e) {  
  24.         return false;  
  25.     } finally {  
  26.         if (outputStream != null) {  
  27.             StreamUtils.closeStream(outputStream);  
  28.         }  
  29.     }  
  30.     return true;  
  31. }  

 

3.清理文件缓存的方法实现如下:

Java代码    收藏代码
  1. /** 
  2.      * If the cache size is greater than the max then trim it down to the trim level. This method is 
  3.      * synchronized so that only one thread can run it at a time. 
  4.      */  
  5.     private void cutCurrentCache() {  
  6.   
  7.         synchronized (TILE_PATH_BASE) {  
  8.   
  9.             if (mUsedCacheSpace > TILE_TRIM_CACHE_SIZE_BYTES) {  
  10.   
  11.                 logger.info("Trimming tile cache from " + mUsedCacheSpace + " to "  
  12.                         + TILE_TRIM_CACHE_SIZE_BYTES);  
  13.   
  14.                 final List<File> z = getDirectoryFileList(TILE_PATH_BASE);  
  15.   
  16.                 // order list by files day created from old to new  
  17.                 final File[] files = z.toArray(new File[0]);  
  18.                 Arrays.sort(files, new Comparator<File>() {  
  19.                     @Override  
  20.                     public int compare(final File f1, final File f2) {  
  21.                         return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());  
  22.                     }  
  23.                 });  
  24.   
  25.                 for (final File file : files) {  
  26.                     if (mUsedCacheSpace <= TILE_TRIM_CACHE_SIZE_BYTES) {  
  27.                         break;  
  28.                     }  
  29.   
  30.                     final long length = file.length();  
  31.                     if (file.delete()) {  
  32.                         mUsedCacheSpace -= length;  
  33.                     }  
  34.                 }  
  35.   
  36.                 logger.info("Finished trimming tile cache");  
  37.             }  
  38.         }  
  39.     }  

 

由上述代码可以看出:看出缓存大于最大值时候清理缓存

Java代码    收藏代码
  1. /** 30 days */  
  2. public static final long TILE_EXPIRY_TIME_MILLISECONDS = 1000L * 60 * 60 * 24 * 30;  
  3.   
  4. /** 600 Mb */  
  5. public static final long TILE_MAX_CACHE_SIZE_BYTES = 600L * 1024 * 1024;  
  6.   
  7. /** 500 Mb */  
  8. public static final long TILE_TRIM_CACHE_SIZE_BYTES = 500L * 1024 * 1024;  

 

Java代码    收藏代码
  1. if (mUsedCacheSpace > TILE_MAX_CACHE_SIZE_BYTES) {  
  2.  cutCurrentCache(); // TODO perhaps we should do this in the background  
  3. }  

原文:http://topmanopensource.iteye.com/blog/1664631

 

 

 

你可能感兴趣的:(osmdroid)