1. 程式人生 > >ArcGIS for Android Runtime 100 升級實踐(一)地圖載入,圖形和符號初始化

ArcGIS for Android Runtime 100 升級實踐(一)地圖載入,圖形和符號初始化

      去年的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頁面會看到這樣的情況:
      祖國江山一片紅,可謂悽慘。       不過沒關係,這主要是原來10.2版本的包名和現在的包名不一樣導致的。我們需要將以前匯入的類刪掉,重新匯入一下:
      重新匯入包以後,我們會發現,呃,好像好了一點,但依然是祖國江山半壁紅。
      其實是Runtime100裡很多類和方法都進行了更改,比如上圖裡我們可以看到之前常用的Line和GraphicsLayer類都已經不存在了,只能用其他類替代;另外改變了很多方法,也新增了很多方法,所以我們就一步一步來看看吧。 三、地圖和圖層的載入(MapView和Layer)       首先我們先回顧下10.2裡的MapView和Layer的關係。       在10.2裡MapView直接繼承於ViewGroup類,本身就是地圖內容的展示容器,使用時候直接在MapView可以載入各種基礎底圖、業務圖層和繪製圖層。

      但是在Runtime100裡,增加了3D地圖顯示的功能。為了滿足大多數人的使用習慣,Esri依然採用MapView類作為2D地圖的展示容器,新增了SceneView類作為3D地圖的展示容器,然後這兩個類共同繼承於一個叫GeoView的基類。
      然後整個MapView的結構也進行了更改。不再是作為一個容器直接新增圖層,而是分成了地圖內容和繪製圖層兩部分進行新增:
      所以,Runtime100裡要新增基礎底圖和業務圖層,需要新建一個ArcGISMap類,在這個類裡新增圖層,然後用MapView.setMap()的方法新增地圖。 第二點,對於圖層來說,Runtime100裡更改了不少圖層類。       比如將基礎圖層中的ArcGISLocalTiledLayer類和ArcGISTiledMapServiceLayer類合併成了一個ArcGISTiledLayer類,也就是將離線和線上載入瓦片資料的類合成了一個,其實也是為了簡化程式設計師的負擔,弱化了離線和線上的概念;       比如將之前的臨時圖形圖層GraphicsLayer換成了GraphicsOverlay,同樣是一個臨時圖層,比起之前的優化來就是它基於GeoView基類並且始終置於頂層,(很棒吧,媽媽再也不用擔心臨時圖層被業務圖層覆蓋的問題了!)呼叫的方法也有所改變,比如官網給的例子:
      第三點,關於圖層的載入。       上面說了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)       在地圖載入完畢後,我們再來看看程式碼:
      可以看出紅色報錯的地方少多了。在我們初始化地圖並載入好圖層後,接下來我們考慮的初始化我們的圖形和符號了。然後我們看看初始化地方的程式碼:
      果然錯誤很多,我們先來看看圖形吧。在Runtime 100裡不能通過例項化空模型來完成圖形的例項化,我們可以看看Polygon API裡的構造方法(Polyline與之完全類似):
      也就是說得通過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裡的建構函式是:
      比起10.2裡也多了一項,是SimpleLineSymbol.Style。這是個列舉類,裡面包含了幾種樣式可以修飾符號。(具體的我測試後再發出效果圖)
public static enum Style {
    DASH,
DASH_DOT,
DASH_DOT_DOT,
DOT,
SOLID,
NULL;
    private Style() {
    }
}
     接下來是SimpleFillSymbol類,看看它在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();

      大功告成!