今天搞了一个ArcGIS API For Android离线地图的实现。
效果如下:
Android的版本是2.1
main.xml,这里要说明的,初始化范围一定要有,不然会不能显示的。
<?xml version="1.0" encoding="utf-8"?> <com.esri.android.map.MapView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="fill_parent" android:layout_height="fill_parent" initExtent="120.64101459999999 31.280566089 120.6769494 31.303135911"> <com.esri.arcgis.sample.AgsOfflineTiledLayer android:id="@+id/layer"/> </com.esri.android.map.MapView>
AgsLOD.java
package com.esri.arcgis.sample; import com.esri.core.internal.d.c; public class AgsLOD extends c { private static final long serialVersionUID = 4341699179151728883L; private int level; private double resolution; private double scale; public AgsLOD(int level, double scale, double resolution) { super(); this.level = level; this.scale = scale; this.resolution = resolution; } public int a() { return this.level; } public double b() { return this.resolution; } public double c() { return this.scale; } }
AgsOfflineTiledLayer.java
package com.esri.arcgis.sample; import java.io.File; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import com.esri.android.map.TiledLayer; import com.esri.core.geometry.Envelope; import com.esri.core.geometry.Point; import com.esri.core.geometry.SpatialReference; import com.esri.core.internal.d.c; import com.esri.core.internal.d.k; import com.esri.core.map.TiledLayerModel; public class AgsOfflineTiledLayer extends TiledLayer { //瓦片文件的路径呀 private String location = "/sdcard/BaseMap/Layers"; //REST里面的空间参考 private SpatialReference spatialReference = SpatialReference.create(4326); //全图范围 private Envelope fullExtent = new Envelope(120.64101459999999, 31.280566089, 120.6769494, 31.303135911); private k tileInfo; public AgsOfflineTiledLayer(Context context, AttributeSet attrs) { super(context, attrs); try { init(); } catch (Exception ex) { ex.printStackTrace(); } } @Override protected TiledLayerModel initModel() throws Exception { return new AgsOfflineTiledLayerModel(location, spatialReference, fullExtent, tileInfo); } private void init() { String confPath = location + File.separator + "conf.xml"; Log.i("conf", confPath); try { tileInfo = new k(); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); File file = new File(confPath); Document doc = docBuilder.parse(file); NodeList nsX = doc.getElementsByTagName("X"); double originX = Double.valueOf(nsX.item(0).getFirstChild() .getNodeValue()); NodeList nsY = doc.getElementsByTagName("Y"); double originY = Double.valueOf(nsY.item(0).getFirstChild() .getNodeValue()); tileInfo.f = new Point(originX, originY); NodeList nsTileRows = doc.getElementsByTagName("TileRows"); tileInfo.a = Integer.valueOf(nsTileRows.item(0).getFirstChild() .getNodeValue()); NodeList nsTileCols = doc.getElementsByTagName("TileCols"); tileInfo.b = Integer.valueOf(nsTileCols.item(0).getFirstChild() .getNodeValue()); NodeList nsLODInfos = doc.getElementsByTagName("LODInfos"); tileInfo.h = new ArrayList<c>(); NodeList lodInfos = nsLODInfos.item(0).getChildNodes(); for (int j = 0, jcount = lodInfos.getLength(); j < jcount; j++) { Node lod = lodInfos.item(j); NodeList list = lod.getChildNodes(); int level = Integer.valueOf(list.item(0).getFirstChild() .getNodeValue()); double scale = Double.valueOf(list.item(1).getFirstChild() .getNodeValue()); double resolution = Double.valueOf(list.item(2).getFirstChild() .getNodeValue()); tileInfo.h.add(new AgsLOD(level, scale, resolution)); } } catch (Exception e) { e.printStackTrace(); } } }
AgsOfflineTiledLayerModel.java
package com.esri.arcgis.sample; import java.io.File; import java.io.FileInputStream; import android.util.Log; import com.esri.core.geometry.Envelope; import com.esri.core.geometry.SpatialReference; import com.esri.core.internal.d.k; import com.esri.core.map.TiledLayerModel; public class AgsOfflineTiledLayerModel extends TiledLayerModel { private static final long serialVersionUID = 7726567118839553087L; private String location; public AgsOfflineTiledLayerModel(String location, SpatialReference sr, Envelope full, k tileInfo) { super(sr, full, tileInfo); this.location = location; } @Override public byte[] getTile(int level, int row, int col) throws Exception { byte[] result = null; try { String bundlesDir = location + File.separator + "_alllayers"; Log.i("location", bundlesDir); String l = "0" + level; int lLength = l.length(); if (lLength > 2) { l = l.substring(lLength - 2); } l = "L" + l; int rGroup = 128 * (row / 128); String r = "000" + Integer.toHexString(rGroup); int rLength = r.length(); if (rLength > 4) { r = r.substring(rLength - 4); } r = "R" + r; int cGroup = 128 * (col / 128); String c = "000" + Integer.toHexString(cGroup); int cLength = c.length(); if (cLength > 4) { c = c.substring(cLength - 4); } c = "C" + c; String bundleBase = String .format("%s/%s/%s%s", bundlesDir, l, r, c); String bundlxFileName = bundleBase + ".bundlx"; String bundleFileName = bundleBase + ".bundle"; int index = 128 * (col - cGroup) + (row - rGroup); FileInputStream isBundlx = new FileInputStream(bundlxFileName); isBundlx.skip(16 + 5 * index); byte[] buffer = new byte[5]; isBundlx.read(buffer); long offset = (long) (buffer[0] & 0xff) + (long) (buffer[1] & 0xff) * 256 + (long) (buffer[2] & 0xff) * 65536 + (long) (buffer[3] & 0xff) * 16777216 + (long) (buffer[4] & 0xff) * 4294967296L; FileInputStream isBundle = new FileInputStream(bundleFileName); isBundle.skip(offset); byte[] lengthBytes = new byte[4]; isBundle.read(lengthBytes); int length = (int) (lengthBytes[0] & 0xff) + (int) (lengthBytes[1] & 0xff) * 256 + (int) (lengthBytes[2] & 0xff) * 65536 + (int) (lengthBytes[3] & 0xff) * 16777216; result = new byte[length]; isBundle.read(result); } catch (Exception ex) { ex.printStackTrace(); } return result; } }
AgsOfflineTiles.java
package com.esri.arcgis.sample; import com.esri.android.map.MapView; import android.app.Activity; import android.os.Bundle; public class AgsOfflineTiles extends Activity { MapView map = null; AgsOfflineTiledLayer layer = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); map = (MapView) findViewById(R.id.map); layer = (AgsOfflineTiledLayer) findViewById(R.id.layer); } }
在SD卡的瓦片数据的路径
源码和测试数据在附件中
BaseMap.rar (1.5 MB)
AgsOfflineTiles.rar (2.4 MB)