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