ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

时间:2024-03-22 19:28:40

      去年的Esri大会,随着最新的ArcGIS 10.5产品的发布,全新的ArcGIS Runtime 100.0也随之发布。ArcGIS Runtime 100.0 可谓是有了个天翻地覆的改进,比如跨平台、3D地图的加载以及多样的地图离线选择等。其实这里面我最感兴趣的是可以加载MMPK数据,MMPK是一种全新的移动地图包,有很多创新和优势,总结起来是一下几点:

  1. 数据存储于压缩的Mobile GDB中,相比起切片数据,体积小了很多;
  2. 保存了所有的fearture要素,底图上展示的都是要素,可供查询和分析;
  3. 可以将所有地图和数据资源打包,
      总结下,就是通过一个文件实现了之前TPK和geodatabase加起来实现的功能,并且体积更小,速度更快。这对于经常要用多个切片数据,时常面临着移动端内存卡空间不足的我来说,绝对是个福音。

      然而,Rumtime100里对大量的接口,类和方法就行了更改,如果直接移植到我们的产品上,那绝对是万里*一片红,而且性能的稳定性也没经过太多测试,于是,我想慢慢实践、测试下,了解后再移植到产品里。
      本篇是一篇初步实践篇,通过将之前我写的空间分析的demo为例(博客地址http://blog.csdn.net/bit_kaki/article/details/76581848)进行移植尝试,获取对于ArcGIS Runtime 100.0的初步印象。

一、环境配置
      
      和之前ArcGIS所需环境差不多,在project的build.gradle里添加url:
allprojects {
    repositories {
        jcenter()
        maven {
            url 'http://esri.bintray.com/arcgis'
        }
    }
}

      然后在module的build.gradle里添加compile:
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.3.1'
 //   compile 'com.esri.arcgis.android:arcgis-android:10.2.8'
    compile 'com.esri.arcgisruntime:arcgis-android:100.0.0'
}

      注意下面个是Runtime100,被我注释掉的是之前用的10.2.8

二、导入包
      
      等gradle更新完毕了以后,进入我们的主activity页面会看到这样的情况:
ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化
  
      祖国*一片红,可谓凄惨。
      不过没关系,这主要是原来10.2版本的包名和现在的包名不一样导致的。我们需要将以前导入的类删掉,重新导入一下:
ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      重新导入包以后,我们会发现,呃,好像好了一点,但依然是祖国*半壁红。
ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      其实是Runtime100里很多类和方法都进行了更改,比如上图里我们可以看到之前常用的Line和GraphicsLayer类都已经不存在了,只能用其他类替代;另外改变了很多方法,也新增了很多方法,所以我们就一步一步来看看吧。

三、地图和图层的加载(MapView和Layer)

      首先我们先回顾下10.2里的MapView和Layer的关系。
      在10.2里MapView直接继承于ViewGroup类,本身就是地图内容的展示容器,使用时候直接在MapView可以加载各种基础底图、业务图层和绘制图层。

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      但是在Runtime100里,增加了3D地图显示的功能。为了满足大多数人的使用习惯,Esri依然采用MapView类作为2D地图的展示容器,新增了SceneView类作为3D地图的展示容器,然后这两个类共同继承于一个叫GeoView的基类。

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化
    
      然后整个MapView的结构也进行了更改。不再是作为一个容器直接添加图层,而是分成了地图内容和绘制图层两部分进行添加:

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      所以,Runtime100里要添加基础底图和业务图层,需要新建一个ArcGISMap类,在这个类里添加图层,然后用MapView.setMap()的方法添加地图。
      
      第二点,对于图层来说,Runtime100里更改了不少图层类。

      比如将基础图层中的ArcGISLocalTiledLayer类和ArcGISTiledMapServiceLayer类合并成了一个ArcGISTiledLayer类,也就是将离线和在线加载瓦片数据的类合成了一个,其实也是为了简化程序员的负担,弱化了离线和在线的概念;
      比如将之前的临时图形图层GraphicsLayer换成了GraphicsOverlay,同样是一个临时图层,比起之前的优化来就是它基于GeoView基类并且始终置于顶层,(很棒吧,妈妈再也不用担心临时图层被业务图层覆盖的问题了!)调用的方法也有所改变,比如官网给的例子:

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      第三点,关于图层的加载。

      上面说了Runtime100里,如果要添加基础底图和业务图层需要通过ArcGISMap类来实现,那么我们来实践下如何加载图层。
      对于加载切片数据,需要当做基础底图进行加载,比起以前的方法,相当于是在MapView里有且仅有一个底图,
这个底图无法进行编辑,仅能提供背景和坐标参考系。
mMapView=(MapView)findViewById(R.id.mapview);
String url=StorageUtil.getSDCardRootPath(getApplicationContext())+"/ArcGIS/localtilelayer/CY_YGYX_BG.tpk";
TileCache mainTileCache = new TileCache(url);
ArcGISTiledLayer layer =new ArcGISTiledLayer(mainTileCache);Basemap basemap=new Basemap(layer);arcGISMap=new ArcGISMap(basemap);mMapView.setMap(arcGISMap);
      对于离线业务数据,方法和原来基本一样,唯一有所不同的就是获取GeodatabaseFeatureTable的方法名由getGeodatabaseTables()变成了getGeodatabaseFeatureTables()。
String url= StorageUtil.getROMRootPath(getApplicationContext())+"/ArcGIS/localtilelayer/ncdc.geodatabase";
Geodatabase localGdb=null;
try {
    localGdb = new Geodatabase(url);
}catch (Exception e){
    e.printStackTrace();
}
if (localGdb != null) {
    for (GeodatabaseFeatureTable gdbFeatureTable : localGdb.getGeodatabaseFeatureTables()) {
        if (gdbFeatureTable.hasGeometry()){
            dataFeatureLayer = new FeatureLayer(gdbFeatureTable);
        }
    }
}
      
      对于临时绘制图层,我们则需要先获取MapView里的GraphicOverlays的列表,向里面增加我们需要添加的临时绘制图层即可。
mMapView=(MapView)findViewById(R.id.mapview);
mMapView.getGraphicsOverlays().add(messureLayer);
mMapView.getGraphicsOverlays().add(pointAnalysistAllGraphicsLayer);
mMapView.getGraphicsOverlays().add(pointAnalysistOneGraphicsLayer);

四、图形和符号(Geometry和Symbol)
      
      在地图加载完毕后,我们再来看看代码:

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      可以看出红色报错的地方少多了。在我们初始化地图并加载好图层后,接下来我们考虑的初始化我们的图形和符号了。然后我们看看初始化地方的代码:

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      果然错误很多,我们先来看看图形吧。在Runtime 100里不能通过实例化空模型来完成图形的实例化,我们可以看看Polygon API里的构造方法(Polyline与之完全类似):

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      也就是说得通过PointCollection或者Part进行构造。
      这两个类都是Runtime 100里新出现的类,但是对于PointCollection看名称我们就知道这是个Point的集合,而我们之前在画面的时候,就是采用点的集合完成的。于是我想就把之前的List<Point>改成PointCollection类,将图形的构造往后放不就可以了。于是尝试一下:
      首先是构造一个PointCollection类,而构造PointCollection需要坐标参考信息SpatialReference(),这个信息我们可以从地图内容里获取,于是:
pointCollection=new PointCollection(arcGISMap.getSpatialReference());

      然后我们可以考虑在获取点的时候构造线和面就可以:
pointCollection.add(mPoint);// 选择点加入点的集合
if (pointCollection.size() > 1) {
    messurePolyline = new Polyline(pointCollection);
    if (pointCollection.size() > 1) {
        messurePolygon = new Polygon(pointCollection);
    }
}

      接下来是符号,可以看出所有的符号构造函数都在报错,我们先看看SimpleLineSymbol类,它Runtime 100里的构造函数是:
ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      比起10.2里也多了一项,是SimpleLineSymbol.Style。这是个枚举类,里面包含了几种样式可以修饰符号。(具体的我测试后再发出效果图)
public static enum Style {
    DASH,
    DASH_DOT,
    DASH_DOT_DOT,
    DOT,
    SOLID,
    NULL;

    private Style() {
    }
}

     接下来是SimpleFillSymbol类,看看它在Runtime 100里符号的构造函数是:

ArcGIS for Android Runtime 100 升级实践(一)地图加载,图形和符号初始化

      可以看出比起10.2的SimpleFillSymbol类,构造函数里还多了个LineSymbol类,我们知道SimpleFillSymbol主要是用来定义面的样式,最后这个LineSymbol类是给这个面加个轮廓,如果不需要加,写null即可。
      以前如果需要在面符号里加上轮廓样式的话,还需要用SimpleFillSymbol.setOutline(SimpleLineSymbol)的方法,也就是说新的构造类是将两个方法合二为一,更加方便。
      
      最后是SimpleMarkerSymbol类,它在Runtime 100里符号的构造函数和10.2里几乎没变,只是将参数的顺序变了下。
      于是修改后,原函数里的符号初始化定义变化为:
pointCollection=new PointCollection(arcGISMap.getSpatialReference());
mMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE,Color.RED, 10);
messureLineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.BLUE, 3);// 初始化线的样式
messureMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE,Color.RED, 10);// 初始化测量时点的样式
messureLayer =new GraphicsOverlay();// 初始化测量图层
pAnalysistSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.RED, 3);
messureFillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.BACKWARD_DIAGONAL,Color.argb(100, 225, 225, 0),new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.BLACK, 2));// 初始化测量时面的样式
messureFillSymbol_red = new SimpleFillSymbol(SimpleFillSymbol.Style.BACKWARD_DIAGONAL,Color.argb(100, 225, 0, 0),new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.BLACK, 2));
messureFillSymbol_blue = new SimpleFillSymbol(SimpleFillSymbol.Style.BACKWARD_DIAGONAL,Color.argb(100, 0, 0, 225),new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.BLACK, 2));
messureFillSymbol_green = new SimpleFillSymbol(SimpleFillSymbol.Style.BACKWARD_DIAGONAL,Color.argb(100, 0, 225, 0),new SimpleLineSymbol(SimpleLineSymbol.Style.NULL,Color.BLACK, 2));
pointAnalysistAllGraphicsLayer = new GraphicsOverlay();
pointAnalysistOneGraphicsLayer = new GraphicsOverlay();

      大功告成!