最近作的arcgis for android項目中因爲移動和電信網絡實在太慢,加上流量消耗也厲害。想到谷歌和百度都使用了緩存的方法。即將瀏覽過的地圖保存到SD卡中,下次瀏覽相同地塊的時候就不須要在從網上下載直接調用本地便可。在API中找了一通無法發現有相似功能的接口,問esri的人也沒有回覆。算了繼承TiledServiceLayer本身實現一個吧。java
由於初始化圖層的時候須要設置TileInfo的值,而這個值直接影響到地圖是否能夠調用成功。我在這塊費大了時間了找不到緣由,其實就是TileInfo的數據設置的不對,應該和你發佈地圖的TileInfo信息一致。這些信息能夠在服務的pjson中得到 如:「http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer?f=pjson」 我寫了個json解析類得到這些須要的數據android
1 /** 2 * ==================================================== 3 * 4 * @Copyright (C) 2012-2013 5 * @All rights reserved 6 * @filename :ReturnJson.java 7 * @date 2013-7-29 8 * @time 下午2:07:36 9 * @author samxu 10 * @description: 11 * 12 * @---------------代碼維護與版本信息--------------------------- 13 * @版本:V1.0 編寫人:samxu 描述:第一次建立 14 * 15 * 16 * @===================================================== 17 */ 18 public class ReturnJson { 19 private String strURL; 20 private int rows; // 瓦片高度 21 private int cols; // 瓦片寬度 22 private int dpi; // //瓦片分辨率 23 private Point origin; // 地圖原點 24 private int wkid; // 地圖座標ID 25 private double[] res; //地圖分辨率 26 private double[] scale; //比例尺 27 private Envelope InitEnvelope; // 初始化範圍 28 private Envelope FullEnvelope; // 最大範圍 29 30 public int getRows() { 31 return rows; 32 } 33 34 public int getCols() { 35 return cols; 36 } 37 38 public int getDpi() { 39 return dpi; 40 } 41 42 public Point getOrigin() { 43 return origin; 44 } 45 46 public int getWkid() { 47 return wkid; 48 } 49 50 public double[] getRes() { 51 return res; 52 } 53 54 public double[] getScale() { 55 return scale; 56 } 57 58 public Envelope getInitEnvelope() { 59 return InitEnvelope; 60 } 61 62 public Envelope getFullEnvelope() { 63 return FullEnvelope; 64 } 65 66 public ReturnJson(String strURL) { 67 // TODO Auto-generated constructor stub 68 this.strURL = strURL; 69 // String jsonString = loadAssetsString(); 70 ExplainJson(); 71 } 72 73 // 解析json中關鍵數據保存起來 74 public void ExplainJson() { 75 HttpPost request = new HttpPost(strURL); 76 try { 77 HttpResponse httpResponse = new DefaultHttpClient() 78 .execute(request); 79 String retStr = EntityUtils.toString(httpResponse.getEntity()); 80 81 JSONObject jsonObject_tileInfo = new JSONObject(retStr) 82 .getJSONObject("tileInfo"); 83 JSONObject jsonObject_initialExtent = new JSONObject(retStr) 84 .getJSONObject("initialExtent"); 85 JSONObject jsonObject_fullExtent = new JSONObject(retStr) 86 .getJSONObject("fullExtent"); 87 JSONArray jsonArray_lods = jsonObject_tileInfo.getJSONArray("lods"); 88 JSONObject jsonObject_spatialReference = jsonObject_tileInfo 89 .getJSONObject("spatialReference"); 90 rows = jsonObject_tileInfo.getInt("rows"); 91 cols = jsonObject_tileInfo.getInt("cols"); 92 dpi = jsonObject_tileInfo.getInt("dpi"); 93 wkid = jsonObject_spatialReference.getInt("wkid"); 94 double x = jsonObject_tileInfo.getJSONObject("origin").getDouble( 95 "x"); 96 double y = jsonObject_tileInfo.getJSONObject("origin").getDouble( 97 "y"); 98 origin = new Point(x, y); 99 double xmin = jsonObject_initialExtent.getDouble("xmin"); 100 double ymin = jsonObject_initialExtent.getDouble("ymin"); 101 double xmax = jsonObject_initialExtent.getDouble("xmax"); 102 double ymax = jsonObject_initialExtent.getDouble("ymax"); 103 InitEnvelope = new Envelope(xmin, ymin, xmax, ymax); 104 xmin = jsonObject_fullExtent.getDouble("xmin"); 105 ymin = jsonObject_fullExtent.getDouble("ymin"); 106 xmax = jsonObject_fullExtent.getDouble("xmax"); 107 ymax = jsonObject_fullExtent.getDouble("ymax"); 108 FullEnvelope = new Envelope(xmin, ymin, xmax, ymax); 109 110 int k = jsonArray_lods.length(); 111 res = new double[k]; 112 scale = new double[k]; 113 for (int i = 0; i < jsonArray_lods.length(); i++) { 114 115 JSONObject jsonObject3 = (JSONObject) jsonArray_lods.opt(i); 116 res[i] = jsonObject3.getDouble("resolution"); 117 scale[i] = jsonObject3.getDouble("scale"); 118 119 } 120 121 } catch (Exception e) { 122 // TODO: handle exception 123 } 124 125 } 126 127 }
而後要作的是繼承TiledServiceLayer初始化圖層;json
1 //初始化圖層設置Tileinfo數據 2 protected void initLayer() { 3 if (getID() == 0) { 4 this.nativeHandle = create(); 5 } 6 try { 7 SpatialReference localSpatialReference = SpatialReference 8 .create(json.getWkid()); 9 setDefaultSpatialReference(localSpatialReference); 10 Envelope FullEnvelope = json.getFullEnvelope(); 11 Envelope initEnvelope = json.getInitEnvelope(); 12 setFullExtent(FullEnvelope); 13 setInitialExtent(initEnvelope); 14 15 Point localPoint = json.getOrigin(); 16 double[] arrayOfDoublescale = json.getScale(); 17 double[] arrayOfDoubleres = json.getRes(); 18 int cols = json.getCols(); 19 int dpi = json.getDpi(); 20 int rows = json.getRows(); 21 int k = arrayOfDoublescale.length; 22 TiledServiceLayer.TileInfo localTileInfo = new TiledServiceLayer.TileInfo( 23 localPoint, arrayOfDoublescale, arrayOfDoubleres, k, dpi, 24 rows, cols); 25 setTileInfo(localTileInfo); 26 super.initLayer(); 27 return; 28 } catch (Exception localException) { 29 localException.printStackTrace(); 30 } 31 32 }
重寫getTile() ,我在這裏花了好長時間就是由於怎麼都進不去,最後發現觸發這個方法的條件是當前顯示範圍下有地圖圖塊若是你沒有移動到有地圖的地方或者tileinfo自己就寫錯了那就不可能進來了緩存
1 //獲取瓦片 若是這方法老是進不去,別想。確定是圖層初始化TileInfo數據添加的不對 2 @Override 3 protected byte[] getTile(int level, int col, int row) throws Exception { 4 // TODO Auto-generated method stub 5 byte[] bytes = null; 6 //根據圖層、行、列找本地數據 7 bytes = getOfflineCacheFile(level, col, row); 8 //若是本地數據爲空,則調用網絡數據。改接口2.0.0測試成功。最新的10.0貌似沒有這個接口。具體自個找找吧,我也沒有測過 9 if (bytes == null) { 10 String strUrl = layerURL + "/tile" + "/" + level + "/" + row + "/" 11 + col; 12 HashMap<String, String> localHashMap = new HashMap<String, String>(); 13 bytes = com.esri.core.internal.b.a.a.a(strUrl, localHashMap); 14 AddOfflineCacheFile(level, col, row, bytes); 15 } 16 return bytes; 17 }
接下來就是對網絡圖片的保存和讀取了網絡
// 將圖片保存到本地 目錄結構能夠隨便定義 只要你找獲得對應的圖片 private byte[] AddOfflineCacheFile(int level, int col, int row, byte[] bytes) { File file = new File(cachepath); if (!file.exists()) { file.mkdirs(); } File levelfile = new File(cachepath + "/" + level); if (!levelfile.exists()) { levelfile.mkdirs(); } File colfile = new File(cachepath + "/" + level + "/" + col); if (!colfile.exists()) { colfile.mkdirs(); } File rowfile = new File(cachepath + "/" + level + "/" + col + "/" + row + ".dat"); if (!rowfile.exists()) { try { FileOutputStream out = new FileOutputStream(rowfile); out.write(bytes); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bytes; } // 從本地獲取圖片 private byte[] getOfflineCacheFile(int level, int col, int row) { byte[] bytes = null; File rowfile = new File(cachepath + "/" + level + "/" + col + "/" + row + ".dat"); if (rowfile.exists()) { try { bytes = CopySdcardbytes(rowfile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { bytes = null; } return bytes; } // 讀取本地圖片流 public byte[] CopySdcardbytes(File file) throws IOException { FileInputStream in = new FileInputStream(file); ByteArrayOutputStream out = new ByteArrayOutputStream(1024); byte[] temp = new byte[1024]; int size = 0; while ((size = in.read(temp)) != -1) { out.write(temp, 0, size); } in.close(); byte[] bytes = out.toByteArray(); return bytes; }
須要值得注意的是若是地圖服務是動態出圖那麼就不能加載。須要源碼的能夠留Email ;ide