管灌系统巡查员智能手机App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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<String, String> tileInfo = new HashMap<>();
        String path = uri.getQueryParameter("TILEMATRIX") + File.separator + uri.getQueryParameter("TILEROW") + File.separator + uri.getQueryParameter("TILECOL");
        return path;
    }
 
}