由于天地图的地图接口请求有次数限制,我们做了本地缓存机制
原理是先查找本地目录是否有保存的瓦片图片,有的话直接返回路径,没有的话去请求天地图加载并保存到本地。
话不多说,直接上代码
我们加载在线瓦片代码是下面这样的,不知道的可以看我上片文章
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,如果没有,缓存到本地并返回googleurl
Log.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,如果没有,缓存到本地并返回googleurl
return 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() {
@Override
public 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);
就这一行代码,不对的地方,欢迎大家指正交流