由于天地图的地图接口请求有次数限制,我们做了本地缓存机制
原理是先查找本地目录是否有保存的瓦片图片,有的话直接返回路径,没有的话去请求天地图加载并保存到本地。
话不多说,直接上代码
我们加载在线瓦片代码是下面这样的,不知道的可以看我上片文章
String real_url = String.format(url, zoom, y, x);
LatLng mLatLng = mAMap.getProjection().fromScreenLocation(new Point(x,y));
Log.e("getTileUrl",x+","+y+""+" "+mLatLng+" "+real_url);
return new URL(real_url);
我们需要对这部分代码进行修改,修改后如下
加载影像底图部分
String ALBUM_PATH= getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath()+"/Cache/";
Bitmap mBitmap; String mFileDirName = String.format("L%02d/", zoom + 1)+"img/"; String mFileName = String.format("%s", TileXYToQuadKey(x, y, zoom));//为了不在手机的图片中显示,取消jpg后缀,文件名自己定义,写入和读取一致即可,由于有自己的bingmap图源服务,所以此处我用的bingmap的文件名String LJ = ALBUM_PATH +mFileDirName+ mFileName; Log.e("getTileUrl是图片否存在: ", "getTileUrl: "+(MapImageCache.getInstance().isBitmapExit( mFileName,ALBUM_PATH +mFileDirName))+""); if (MapImageCache.getInstance().isBitmapExit( mFileName,ALBUM_PATH +mFileDirName)) {//判断本地是否有图片文件,如果有返回本地url,如果没有,缓存到本地并返回googleurlLog.e("存在: ","file://" + LJ);return new URL("file://" + LJ); }else{String real_url = String.format(url, zoom, y, x);mBitmap = getImageBitmap(getImageStream(real_url));try {saveFile(mBitmap, mFileName, mFileDirName);} catch (IOException e) {e.printStackTrace();}Log.e("不存在: ",real_url);return new URL(real_url);
加载标注部分
Bitmap mBitmap; String mFileDirName = String.format("L%02d/", zoom + 1)+"title/"; String mFileName = String.format("%s", TileXYToQuadKey(x, y, zoom));//为了不在手机的图片中显示,取消jpg后缀,文件名自己定义,写入和读取一致即可,由于有自己的bingmap图源服务,所以此处我用的bingmap的文件名String LJ = ALBUM_PATH +mFileDirName+ mFileName; Log.e("名称是否存在: ", mFileName+"getTileUrl: "+(MapImageCache.getInstance().isBitmapExit( mFileName,ALBUM_PATH +mFileDirName))+""); if (MapImageCache.getInstance().isBitmapExit( mFileName,ALBUM_PATH +mFileDirName)) {//判断本地是否有图片文件,如果有返回本地url,如果没有,缓存到本地并返回googleurlreturn new URL("file://" + LJ); }else{String real_url = String.format(url2, zoom, y, x);mBitmap = getImageBitmap(getImageStream(real_url));try {saveFile(mBitmap, mFileName, mFileDirName);} catch (IOException e) {e.printStackTrace();}return new URL(real_url); }
下面是缓存过程用到的一些方法
/*** 瓦片数据坐标转换*/ private String TileXYToQuadKey(int tileX, int tileY, int levelOfDetail) {StringBuilder quadKey = new StringBuilder();for (int i = levelOfDetail; i > 0; i--){char digit = '0';int mask = 1 << (i - 1);if ((tileX & mask) != 0){digit++;}if ((tileY & mask) != 0){digit++;digit++;}quadKey.append(digit);}return quadKey.toString(); }
/*** 保存文件*/ public void saveFile(final Bitmap bm, final String fileName, final String fileDirName) throws IOException {new Thread(new Runnable() {@Overridepublic void run() {try {if(bm != null) {File dirFile = new File(ALBUM_PATH + fileDirName);if(!dirFile.exists()){dirFile.mkdirs();Log.e("创建文件夹",(dirFile.exists())+"");}File myCaptureFile = new File(ALBUM_PATH + fileDirName + fileName);// Log.e("保存路径",myCaptureFile.getPath());BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));bm.compress(Bitmap.CompressFormat.PNG, 80, bos);bos.flush();bos.close();}} catch (IOException e) {e.printStackTrace();}}}).start(); } public Bitmap getImageBitmap(InputStream imputStream){// 将所有InputStream写到byte数组当中byte[] targetData = null;if(imputStream != null){byte[] bytePart = new byte[4096];while (true) {try {int readLength = imputStream.read(bytePart);if (readLength == -1) {break;} else {byte[] temp = new byte[readLength + (targetData == null ? 0 : targetData.length)];if (targetData != null) {System.arraycopy(targetData, 0, temp, 0, targetData.length);System.arraycopy(bytePart, 0, temp, targetData.length, readLength);} else {System.arraycopy(bytePart, 0, temp, 0, readLength);}targetData = temp;}} catch (Exception e) {e.printStackTrace();}}}// 指使Bitmap通过byte数组获取数据Bitmap bitmap = BitmapFactory.decodeByteArray(targetData, 0, targetData.length);return bitmap; }public InputStream getImageStream(String path) throws Exception{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setRequestMethod("GET");if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){return conn.getInputStream();}return null; }
MapImageCache类 ,这个类就是判断了一下本地路径是否存在图片缓存
import java.io.File;public class MapImageCache {private static MapImageCache mNetImageViewCache = new MapImageCache();private MapImageCache() {}public static MapImageCache getInstance() {return mNetImageViewCache;}/*** 判断图片是否存在首先判断内存中是否存在然后判断本地是否存在** @param url* @return*/public boolean isBitmapExit(String url,String path) {//boolean isExit = containsKey(url);boolean isExit = false;if (false == isExit) {isExit = isLocalHasBmp(url,path);}return isExit;}/** 判断本地有没有*/private boolean isLocalHasBmp(String name,String path) {boolean isExit = true;// String name = name;String filePath = path;File file = new File(filePath, name);if (file.exists()) {} else {isExit = false;}return isExit;} }
在加载离线实现的过程中参考了一个大佬博客Android的关于高德地图加载谷歌瓦片,并缓存本地的功能._android h5缓存地图瓦片-CSDN博客
使用大佬的方法,每次加载离线瓦片数据地图就是黑色的只有标注,后来发现是加载缓存标注图片时,标注图片的背景变成了黑色,原因就是保存的时候图片格式是JPEG,只需要把JPEG改成PNG即可解决了
bm.compress(Bitmap.CompressFormat.PNG, 80, bos);
就这一行代码,不对的地方,欢迎大家指正交流