今天搞了一个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卡的瓦片数据的路径

源码和测试数据在附件中
11 楼
眼高手低
2011-09-08
您好,我想请教一个问题。就是com.esri.core.internal.d.c和com.esri.core.internal.d.k是什么类啊?我看到工程目录中有很多这样后面是简单字母的包及类。这些在参考中又查不到。当然除了这些之外还有许多查不到的包及类。我能不能知道您是通过什么渠道学习那些参考中查不到的包及类的?我是个新人,刚刚接触ArcGIS API for Android,手上只有一个《ArcGIS API for Android+案例教程》,您能不能给推荐一些资料?我万分感谢!
12 楼
眼高手低
2011-09-08
AgsOfflineTiledLayerModel.java部分从int index = 128 * (col - cGroup) + (row - rGroup);开始我就没看懂,您能给解释一下吗?
13 楼
Virgo_S
2011-09-14
眼高手低 写道
您好,我想请教一个问题。就是com.esri.core.internal.d.c和com.esri.core.internal.d.k是什么类啊?我看到工程目录中有很多这样后面是简单字母的包及类。这些在参考中又查不到。当然除了这些之外还有许多查不到的包及类。我能不能知道您是通过什么渠道学习那些参考中查不到的包及类的?我是个新人,刚刚接触ArcGIS API for Android,手上只有一个《ArcGIS API for Android+案例教程》,您能不能给推荐一些资料?我万分感谢!
有一些包你在eclipse里提示可以找到
14 楼
Virgo_S
2011-09-14
眼高手低 写道
AgsOfflineTiledLayerModel.java部分从int index = 128 * (col - cGroup) + (row - rGroup);开始我就没看懂,您能给解释一下吗?
这个是瓦片的算法,建议你看一下关于esri的瓦片生成原理
15 楼
眼高手低
2011-09-16
我是个新手,不太明白您说的“有一些包你在eclipse里提示可以找到”。您指的是"import com.esri.core.internal.d.k;",然后将光标放在上面后给出的那个提示吗?我的Eclipse给出的是"Note: This element has no attached source and the Javadoc could not be found in the attached Javadoc"。这应该是没有相关信息的意思吧?
16 楼
眼高手低
2011-09-16
您能给我提供一个ArcGIS Server 10的下载地址吗?我在网上找了好几天也没找到。
17 楼
Virgo_S
2011-09-17
眼高手低 写道
您能给我提供一个ArcGIS Server 10的下载地址吗?我在网上找了好几天也没找到。
呵呵,这个你要找esri中国了,不然有侵权的嫌疑了
18 楼
hsjshijiazhuang
2011-10-08
哥们。你这程序,有时候,直接调用,会崩溃。然后再次执行,就能加载好。为啥呢???
19 楼
壮壮203
2011-10-08
hsjshijiazhuang 写道
哥们。你这程序,有时候,直接调用,会崩溃。然后再次执行,就能加载好。为啥呢???
我也是这样,求解释
20 楼
qyc898
2011-10-19
楼主,我只要一建arcgis的项目,就在building workspace的时候整个eclipse卡死了...卡很久然后eclipse说内存不足就关掉了...是什么原因啊?
eclipse是3.6.2的版本,ADT是12,jdk是1.6的,操作系统是windows xp..机器配置也没有问题,2G内容双核CPU,开发普通的安卓项目和谷歌地图都正常
eclipse是3.6.2的版本,ADT是12,jdk是1.6的,操作系统是windows xp..机器配置也没有问题,2G内容双核CPU,开发普通的安卓项目和谷歌地图都正常
21 楼
刀枪剑戟
2011-10-24
qyc898 写道
楼主,我只要一建arcgis的项目,就在building workspace的时候整个eclipse卡死了...卡很久然后eclipse说内存不足就关掉了...是什么原因啊?
eclipse是3.6.2的版本,ADT是12,jdk是1.6的,操作系统是windows xp..机器配置也没有问题,2G内容双核CPU,开发普通的安卓项目和谷歌地图都正常
eclipse是3.6.2的版本,ADT是12,jdk是1.6的,操作系统是windows xp..机器配置也没有问题,2G内容双核CPU,开发普通的安卓项目和谷歌地图都正常
你需要改Eclipse的一个参数,在Eclipse目录下有eclipse.ini文件,打开,拖到最后,改成:
-Xms256m
-Xmx1024m
后者可以改得更大。参见addegg.net
22 楼
sunshine19851
2011-10-28
你这个是arcgis server 10的切片形式,但是针对arcgis server 10以下的切片形式又改如何处理呢?
23 楼
我叫钱多多
2011-11-22
不错 很强大 学习了
24 楼
ls6576837
2011-12-01
请问楼主,public byte[] getTile(int level, int row, int col)这个函数返回的就是对应的切片地图的吗?
25 楼
jiahui524
2011-12-09
想问一下,万一离线数据特别大,你不用异步任务去完成不会ANR或者FC???如果用到异步任务或者Handler 又如何实现?能说下吗?
26 楼
hardycheng
2012-02-08
我想问一下 :
如何在Activity中知道现在调用的是第几层的切片。
比如我想让一些信息在第三层的时候才显示,而00,01,02这些切片中地图显示的范围比较大,业务信息点不让显示,怎么实现?
如何在Activity中知道现在调用的是第几层的切片。
比如我想让一些信息在第三层的时候才显示,而00,01,02这些切片中地图显示的范围比较大,业务信息点不让显示,怎么实现?
27 楼
眼高手低
2012-02-20
您好,我还是对com.esri.core.internal.d.c和com.esri.core.internal.d.k比较纠结。您是怎么获取这两个类的用途、属性和方法的详细信息的?或者说您在写代码的时候是怎么知道要用到这些类以及怎么用的?敬求赐教!
28 楼
ilywhax
2012-03-24
请问下你这离线地图可不可以加载不是切片的地图?我换成我的地图(不是用切片做的)没法显示
29 楼
yuejie001
2012-03-29
楼主你好:
这个例子我做好了,存在一个问题,就是地图从全图开始放大,放大几级以后,到了数据多的、精细的地方就显示不了了,不知道什么原因,谢谢赐教。
这个例子我做好了,存在一个问题,就是地图从全图开始放大,放大几级以后,到了数据多的、精细的地方就显示不了了,不知道什么原因,谢谢赐教。
30 楼
minjie0128
2012-04-07
这个resolution是什么意思