package com.dayu.pipirrapp.utils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.util.Log; import com.dayu.pipirrapp.MyApplication; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import okhttp3.ResponseBody; /** * author: zuo * Date: 2024-09-06 * Time: 17:59 * 备注: 完成地图缓存策略 */ public class MapJpgUtils { static String TAG = "MapJpgUtils"; static MapJpgUtils mapJpgUtils; String childName = "mapCache"; String fileType = ".jpg"; public static MapJpgUtils getInsatance() { if (mapJpgUtils == null) { mapJpgUtils = new MapJpgUtils(); } return mapJpgUtils; } // 获取缓存瓦片文件 public File getCachedTile(String url) { String fileName = hashUrl(url); // URL 转换为唯一的哈希值或文件名 String folderPath = extractTileInfoFromUrl(url); File cacheDir = new File(MyApplication.myApplication.getCacheDir() + File.separator + childName + File.separator + folderPath); // 瓦片存储目录 if (!cacheDir.exists()) { cacheDir.mkdirs(); } return new File(cacheDir, fileName); } // 使用 MD5 哈希 URL 作为文件名 private String hashUrl(String url) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(url.getBytes()); byte[] hashBytes = digest.digest(); StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { sb.append(String.format("%02x", b)); } return sb.toString() + fileType; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return String.valueOf(url.hashCode()); } } // 保存瓦片到缓存 public boolean saveTileToCache(String url, ResponseBody body) { try { //从 URL 中提取瓦片的 Z/X/Y 值 String folderPath = extractTileInfoFromUrl(url); File tileFile = new File(MyApplication.myApplication.getCacheDir() + File.separator + childName + File.separator + folderPath + File.separator + hashUrl(url)); if (!tileFile.getParentFile().exists()) { tileFile.getParentFile().mkdirs(); } InputStream inputStream = null; OutputStream outputStream = null; try { byte[] fileReader = new byte[4096]; long fileSizeDownloaded = 0; inputStream = body.byteStream(); outputStream = new FileOutputStream(tileFile); while (true) { int read = inputStream.read(fileReader); if (read == -1) { break; } outputStream.write(fileReader, 0, read); fileSizeDownloaded += read; } outputStream.flush(); // 保存完成后,记录缓存创建时间 tileFile.setLastModified(System.currentTimeMillis()); if (validateImageFile(tileFile)) { // 校验下载文件大小和实际大小是否一致 long actualFileSize = tileFile.length(); if (fileSizeDownloaded == actualFileSize) { Log.d(TAG, "文件大小匹配,下载大小:" + fileSizeDownloaded + " 字节,实际大小:" + actualFileSize + " 字节"); return true; } else { //保存失败,删除文件 tileFile.delete(); Log.e(TAG, "文件大小不匹配,下载大小:" + fileSizeDownloaded + " 字节,实际大小:" + actualFileSize + " 字节"); return false; } } else { //保存失败,删除文件 tileFile.delete(); Log.d(TAG, "保存失败,文件没有保存完整"); return false; } } catch (Exception e) { return false; } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } catch (Exception e) { return false; } } /** * 判断文件是否存在 * * @param url * @return */ public boolean isHasFiles(String url) { String fileName = hashUrl(url); // URL 转换为唯一的哈希值或文件名 File cacheDir = new File(MyApplication.myApplication.getCacheDir(), "mapCache"); // 瓦片存储目录 if (!cacheDir.exists()) { cacheDir.mkdirs(); } if (new File(cacheDir, fileName).exists()) { return true; } return false; } // 判断缓存是否过期 public boolean isCacheExpired(File cachedFile) { final long cacheValidity = 24 * 60 * 60 * 1000; // 1 天有效期 long lastModified = cachedFile.lastModified(); return (System.currentTimeMillis() - lastModified) > cacheValidity; } /** * 判断当前文件是否完整 * * @param url * @return */ public boolean isComplete(String url, long size) { return false; } // 清理所有旧缓存 public void clearOldCacheFiles() { File cacheDir = new File(MyApplication.myApplication.getCacheDir(), "mapCache"); if (cacheDir.exists()) { File[] files = cacheDir.listFiles(); if (files != null) { for (File file : files) { file.delete(); } } } } //清理单个缓存 public void clearCacheFile(String url) { File file = new File(MyApplication.myApplication.getCacheDir() + File.separator + childName + File.separator + hashUrl(url) + fileType); if (file.exists()) { file.delete(); } } // 校验图片的完整性 public boolean validateImageFile(File tileFile) { if (!tileFile.exists()) { // 文件不存在,视为不完整 return false; } // 尝试解析图像 Bitmap bitmap = BitmapFactory.decodeFile(tileFile.getAbsolutePath()); if (bitmap != null) { // 图像解析成功,文件完整 Log.d(TAG, "图像解析成功,文件完整"); // 解析完图像后,手动回收Bitmap的内存 bitmap.recycle(); return true; } else { // 图像解析失败,文件不完整或损坏 Log.e(TAG, "图像解析失败,文件不完整或损坏"); return false; } } /** * 判断请求是否为天地图瓦片 * * @param url * @return */ public boolean isTianDiTuTileRequest(String url) { return url.contains("tianditu.gov.cn") && url.contains("wmts") && url.contains("TILEMATRIX"); } /** * 从 URL 中提取瓦片的 Z/X/Y 值 * * @param url * @return */ public String extractTileInfoFromUrl(String url) { Uri uri = Uri.parse(url); Map tileInfo = new HashMap<>(); String path = uri.getQueryParameter("TILEMATRIX") + File.separator + uri.getQueryParameter("TILEROW") + File.separator + uri.getQueryParameter("TILECOL"); return path; } }