Building Applications with the ArcGIS Runtime SDK for Android

Report 22 Downloads 316 Views
Esri Developer Summit in Europe November 19 | Berlin

Building Applications with the ArcGIS Runtime SDK for Android Andy Gup, Rainald Suchan

Agenda



Introduction



Runtime SDK -

Tools and features



Maps & Layers



GPS



Tasks



Editing



Offline Capabilities



Summary

Your presenters… Rainald Suchan, Esri Germany Software Developer [email protected]

Andy Gup, Esri U.S. Tech Lead for Web APIs and Android Esri Developer Network [email protected] @agup

Maps Can Be Shared Across Devices Making Maps available to all

Windows Phone

Android

iOS

Web Sites

ArcGIS Server

Desktop

Browsers

One Map

Online Services

. . . Enhancing Access and Collaboration

SDK Features



Create new ArcGIS Android projects



Create new ArcGIS Android Sample projects



Convert existing Android projects into ArcGIS for Android projects



Callout Localization -



Right click project > ArcGIS tools > UI Localization

Integrated Help System and Javadoc

Android SDK

http://developer.android.com

Download the SDK

http://esriurl.com/android

Project Configuration - AndroidManifest.xml

... ...

<uses-permission android:name= "android.permission.INTERNET" /> <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />

Project Configuration - res/layout/main.xml



Performance and the UI Thread



All UI work must be done on UI thread!



AsyncTask – runs in other threads



Handler() – bound to creation thread



View.runonUiThread(new runnable(){…})



ExecutorService – manage multiple AsyncTasks



Threads

The main mapping component - MapView class

public class HelloWorld extends Activity { MapView map = null; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); map = (MapView) findViewById(R.id.map); } }

http://esriurl.com/AndroidMapView

Adding map layers

map = new MapView(this); map.addLayer(new ArcGISTiledMapServiceLayer( "http://services.arcgisonline.com/ArcGIS/rest/services/...”)); setContentView(map);

Adding map layers Tiled Map Service map = new MapView(this); map.addLayer(new ArcGISTiledMapServiceLayer( "http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer")); setContentView(map);

Dynamic Map Service map.addLayer(new ArcGISDynamicMapServiceLayer( "http://.../ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer"));

Feature Service map.addLayer(new ArcGISFeatureLayer(url,MODE.SNAPSHOT));

Image Service map.addLayer(new ArcGISImageServicesLayer(url, null));

Adding layers…

GraphicsLayer GroupLayer ArcGISLocalTiledLayer

WebMapLayer

Listening for MapView events

INTIALIZED INITIALIZATION_FAILED OnStatusChangedListener.STATUS.INITIALIZED LAYER_LOADED OnStatusChangedListener.STATUS.INITIALIZATION_FAILED LAYER_LOADING_FAILED OnStatusChangedListener.STATUS.LAYER_LOADED OnStatusChangedListener.STATUS.LAYER_LOADING_FAILED

Listening for MapView events

map.setOnStatusChangedListener(new OnStatusChangedListener() { private static final long serialVersionUID = 1L; public void onStatusChanged(Object source, STATUS status) { if (OnStatusChangedListener.STATUS.INITIALIZED == status && source == map) { //TODO } if (OnStatusChangedListener.STATUS.LAYER_LOADED == status && source == map){ //TODO } } }

Listening for Layer events

INTIALIZED INITIALIZATION_FAILED LAYER_LOADED OnStatusChangedListener.STATUS.INITIALIZED LAYER_LOADING_FAILED OnStatusChangedListener.STATUS.INITIALIZATION_FAILED

Listening for Layer events

tiledLayer.setOnStatusChangedListener(new OnStatusChangedListener() { private static final long serialVersionUID = 1L; public void onStatusChanged(Object source, STATUS status) { if (OnStatusChangedListener.STATUS.INITIALIZED == status && source == tiledLayer) { //TODO } if (OnStatusChangedListener.STATUS.INITIALIZATION_FAILED == status && source == tiledLayer){ //TODO } } }

Listener Demo

Microsoft Clip art

Map touch events - MapOnTouchListener

Listening for map touch events class MyTouchListener extends MapOnTouchListener { Graphic g; // first point clicked on the map Point p0 = null; int uid = -1; public MyTouchListener(Context arg0, MapView arg1) { super(arg0, arg1); } public boolean onDragPointerMove(MotionEvent from, MotionEvent to) { if (uid == -1) { // first time //TODO } else { //TODO } return true; } ... }

Switching between touch listeners /** * Sets the DEFAULT MapOnTouchListener */ public void setDefaultTouchListener(){ MapOnTouchListener ml = new MapOnTouchListener(getContext(), _mapView); _mapView.setOnTouchListener(ml); } /** * Set the MyTouchListener which overrides various user touch events. */ public void setDrawTouchListener(){ _myTouchListener = new MyTouchListener(getContext(), _mapView); _mapView.setOnTouchListener(_myTouchListener); }

/** * Remove DEFAULT MapOnTouchListener */

map.setOnSingleTapListener(null);

Touch listeners demo

Microsoft Clip art

GPS and Device Location

MapView mv = _mapView; _locationService = _mapView.getLocationService(); _locationService.setAutoPan(true); _locationService.setLocationListener(new LocationListener() { //TODO }); _locationService.start();

GPS/Location restart



After application cold start, paused, view change.



Step 1: Map + layer(s) MUST be loaded first



Step 2: Start the GPS and/or LocationService



Step 3: autoCenter and/or draw GPS graphic

Restart LocationService #1 – easy way

map.setOnStatusChangedListener(new OnStatusChangedListener() { public void onStatusChanged(Object source, STATUS status) { if (source == map && status == STATUS.INITIALIZED) { LocationService ls = map.getLocationService(); ls.setAutoPan(false); ls.setLocationListener(new LocationListener() { public void onLocationChanged(Location loc) { //TODO } } } } }

Restart LocationService #2 - more control

In onResume() use a perpetual Handler… Step 1: unpause() map Step 2: Implement two nested handlers inside a Runnable Step 3: Implement a counter Step 4: Implement if count > X then fail gracefully Step 5: start the Runnable

Location demo

Microsoft Clip art

Tasks •

All ArcGIS Tasks are AsyncTask -

Geocode

-

GeoProcessing

-

Identify

-

Query

Geoprocessing Example – Step 1

class ViewShedQuery extends AsyncTask { GPParameter[] outParams = null; @Override protected void onPostExecute(GPParameter[] result) { //TODO } @Override protected GPParameter[] doInBackground( ArrayList... params1) { //TODO } }

Geoprocessing Example – Step 2

GPFeatureRecordSetLayer gpf = new GPFeatureRecordSetLayer(“xyz"); gpf.setSpatialReference(map.getSpatialReference()); gpf.setGeometryType(Geometry.Type.Point); // 1st input parameter - Add the point selected by the user Graphic f = new Graphic(mappoint,new SimpleMarkerSymbol(...)); gpf.addGraphic(f); // Second input parameter GPLinearUnit gpl = new GPLinearUnit("Viewshed_Distance"); gpl.setUnits("esriMeters"); gpl.setDistance(8046.72); // Add params params = new ArrayList(); params.add(gpf); params.add(gpl); new ViewShedQuery().execute(params);

Geoprocessing Example – Step 3

@Override protected GPParameter[] doInBackground( ArrayList... params1) { gp = new Geoprocessor(_gpEndPoint); gp.setOutSR(map.getSpatialReference()); try { GPResultResource rr = gp.execute(params1[0]); outParams = rr.getOutputParameters(); } catch (Exception e) { e.printStackTrace(); } return outParams; }

Geoprocessing Example – Step 4 @Override protected void onPostExecute(GPParameter[] result) { if (outParams == null) return; for (int i = 0; i < outParams.length; i++) { if (outParams[i] instanceof GPFeatureRecordSetLayer) { GPFeatureRecordSetLayer fsl = (GPFeatureRecordSetLayer) outParams[i]; for (Graphic feature : fsl.getGraphics()) { Graphic g = new Graphic(feature.getGeometry(), new SimpleFillSymbol(Color.CYAN) ); gLayer.addGraphic(g); } } } }

Geoprocessing demo

Editing Feature Layers ArcGISFeatureLayer.applyEdits() •

Asynchronous



Create new feature



Delete features



Edit existing geometries



Edit attributes

Editing Feature Layers Immediate over-the-air sync (requires internet!) •

Adding



Deleting



Updating

Feature Service specification support -

geometries

-

renderer

-

attributes

//Access ArcGISFeatureLayer featureLayer.getFields(); //Field[] featureLayer.getTypes(); //FeatureType[] featureLayer.getTypeIdField(); //String

Editing Feature Layers – data integrity

Features must confirm to layer specification •

Geometry type



Accuracy



Topology rules

Editing Feature Layers

//create a graphic using the template Graphic graphic = featureLayer.createFeatureWithTemplate( template, geometry); featureLayer.applyEdits(new Graphic[] { graphic }, null, null, new CallbackListener() { public void onError(Throwable error) { // TODO implement error code } public void onCallback(FeatureEditResult[][] editResult) { // NOTE: This is ALWAYS called even if error if (editResult[2] != null && editResult[2][0] != null && editResult[2][0].isSuccess()) { // editResult[0] = ADD results // editResult[1] = DELETE results // editResult[2] = UPDATE results } });

AttributeEditor demo

Geometry Editing

Offline •

Data can be stored on an SD Card -

ArcGIS Compact Cache Format

-

Tile Package (*.tpk)

-

JSON FeatureSet

baseMapLayer = new ArcGISLocalTiledLayer( “file:///mnt/sdcard/ArcGIS/samples/cljf/”+ “OfflineData/ImageryTPK.tpk”);

Offline capabilities •



Use in memory FeatureLayer -

Feature set [array of features]

-

Layer definition (JSON from feature service)

Change Features -

Add/remove graphics

-

applyEdits()



Write to/from disk in JSON



Add/remove graphics



Advanced Symbology

Offline – create FeatureLayer

<string name="config.windturbine.layer.definition"> {\"currentVersion\":10.01,\"id\":0,\"name\":\"WindTurbine\”…

//Java classturbinesFeatureLayer = new ArcGISFeatureLayer( R.string.config.windturbine.layer.definition, FeatureSet, null);

Offline – Add/edit features

featureLayer.addGraphics(graphics); //or Graphic[] graphics = new Graphic[ g ]; featureLayer.applyEdits( //adds graphics, //updates, //deletes );

Offline – write JSON to SD Card windTurbine.queryFeatures(query, new CallbackListener() { // create json from resulting FeatureSet @Override public void onCallback(FeatureSet result) { if(result != null){ FileOutputStream outstream = null; try { // create feature set as json string String fsstring = FeatureSet.toJson(result); // create fully qualified path for json file path = createJsonFile(); // create a File from json fully qualified path File outfile = new File(path); // create output stream to write to json file outstream = new FileOutputStream(outfile); outstream.write(fsstring.getBytes()); outstream.close(); } catch (Exception e) { //TODO } } }}); }

Offline – read JSON from SD Card

//Use Jackson JsonParser JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createJsonParser( new FileInputStream(path) ); parser.nextToken(); fs = FeatureSet.fromJson(parser);

Demo Offline

http://esriurl.com/createLocalJson

Webmaps Uses a different pattern map = new MapView( this, "http://www.arcgis.com/home/item.html?id=81d22...”, “name”, “password” ); setContentView(map);

As compared to...

map = new MapView(this); map.addLayer(new ArcGISTiledMapServiceLayer( "http://services.arcgisonline.com/ArcGIS/rest/services/...”)); setContentView(map);

ArcGIS for Android Application

Road Ahead Q4/2012 •

Better cartography



Functional parity across platforms



ArcGIS Online support



ArcGIS 10.1 / sp1 support

Q2/2013 •

Offline workflows (convert to JSON)



Data sync (feature objects offline w/ sync – full offline story gets completed. Fall will have offline w/ no sync)



3D

Fall Release Highlights



Better SDK – more samples and available from online



Routing Task – service area, closest facility



Find Task



Z-order Graphic



Develop or creation of popups



Wrap around world



Better popups



Highlight features



KML (via service), OSM, WMS



Time aware / temporal renderers

Tips-and-tricks •

Test using a phone and tablet vs. Emulator



Android Help: http://developer.android.com/



Android Help -> User Interface Best Practices



Which Android version? Know your users!



Troubleshooting ArcGIS? Use the Android Debug Bridge (ADB) and Logcat

Log.e("Debug", String.valueOf(_currentLocation.getLatitude()));

Github

Android Quick Start Sample: https://github.com/esri

Rainald Suchan, Esri Germany Software Developer??? ???@esri.?? Twitter ???

Andy Gup, Esri U.S. Tech Lead for Web APIs and Android Esri Developer Network [email protected] @agup