Upload
others
View
33
Download
0
Embed Size (px)
Citation preview
Andy Gup, Rainald Suchan
Building Applications with the ArcGIS Runtime SDK for Android
Esri Developer Summit in EuropeNovember 19 | Berlin
Agenda
• Introduction• Runtime SDK
- Tools and features
• Maps & Layers• GPS• Tasks• Editing• Offline Capabilities• Summary
Your presenters…
Rainald Suchan, Esri GermanySoftware [email protected]
Andy Gup, Esri U.S.Tech Lead for Web APIs and AndroidEsri Developer Network [email protected] @agup
Maps Can Be Shared Across Devices
. . . Enhancing Access and Collaboration
One Map
Desktop
iOS
WindowsPhone Android
Web Sites
Browsers
OnlineServices
Making Maps available to all
ArcGIS Server
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
Project Configuration - AndroidManifest.xml
<activity android:name=".EsriQuickStartSampleActivity"android:label="@string/app_name"android:configChanges="orientation">
...
...</activity>
<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
<com.esri.android.map.MapViewandroid:id="@+id/map" android:layout_height="fill_parent"android:layout_width="fill_parent" />
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
map = new MapView(this);map.addLayer(new ArcGISTiledMapServiceLayer("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));setContentView(map);
Tiled Map Service
map.addLayer(new ArcGISFeatureLayer(url,MODE.SNAPSHOT));
Feature Service
map.addLayer(new ArcGISDynamicMapServiceLayer("http://.../ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer"));
Dynamic Map Service
map.addLayer(new ArcGISImageServicesLayer(url, null));
Image Service
Adding layers…
GraphicsLayer
GroupLayer
ArcGISLocalTiledLayer
WebMapLayer
Listening for MapView events
INTIALIZED
INITIALIZATION_FAILED
LAYER_LOADED
LAYER_LOADING_FAILED
OnStatusChangedListener.STATUS.INITIALIZED
OnStatusChangedListener.STATUS.INITIALIZATION_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
LAYER_LOADING_FAILED
OnStatusChangedListener.STATUS.INITIALIZED
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 mapPoint 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<ArrayList<GPParameter>, Void, GPParameter[]> {
GPParameter[] outParams = null;
@Overrideprotected void onPostExecute(GPParameter[] result) {
//TODO}
@Overrideprotected GPParameter[] doInBackground(
ArrayList<GPParameter>... 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 userGraphic f = new Graphic(mappoint,new SimpleMarkerSymbol(...));gpf.addGraphic(f);
// Second input parameterGPLinearUnit gpl = new GPLinearUnit("Viewshed_Distance");gpl.setUnits("esriMeters");gpl.setDistance(8046.72);
// Add paramsparams = new ArrayList<GPParameter>();params.add(gpf);params.add(gpl);
new ViewShedQuery().execute(params);
Geoprocessing Example – Step 3
@Overrideprotected GPParameter[] doInBackground(
ArrayList<GPParameter>... 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
@Overrideprotected 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• UpdatingFeature Service specification support
- geometries- renderer- attributes
//Access ArcGISFeatureLayerfeatureLayer.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 templateGraphic graphic = featureLayer.createFeatureWithTemplate(
template, geometry);
featureLayer.applyEdits(new Graphic[] { graphic }, null, null, new CallbackListener<FeatureEditResult[][]>() {
public void onError(Throwable error) {// TODO implement error code
}
public void onCallback(FeatureEditResult[][] editResult) {
// NOTE: This is ALWAYS called even if errorif (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
baseMapLayer = new ArcGISLocalTiledLayer(“file:///mnt/sdcard/ArcGIS/samples/cljf/”+“OfflineData/ImageryTPK.tpk”);
• Data can be stored on an SD Card- ArcGIS Compact Cache Format
- Tile Package (*.tpk)
- JSON FeatureSet
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
<!—strings.xml--><string name="config.windturbine.layer.definition">{\"currentVersion\":10.01,\"id\":0,\"name\":\"WindTurbine\”…</string>
//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 CardwindTurbine.queryFeatures(query, new CallbackListener<FeatureSet>() {
// create json from resulting FeatureSet@Overridepublic void onCallback(FeatureSet result) {
if(result != null){FileOutputStream outstream = null;try {
// create feature set as json stringString fsstring = FeatureSet.toJson(result);// create fully qualified path for json filepath = createJsonFile();// create a File from json fully qualified pathFile outfile = new File(path);// create output stream to write to json fileoutstream = new FileOutputStream(outfile);outstream.write(fsstring.getBytes());outstream.close();
} catch (Exception e) {//TODO
}}
}});}
Offline – read JSON from SD Card
//Use Jackson JsonParserJsonFactory factory = new JsonFactory();JsonParser parser = factory.createJsonParser(
new FileInputStream(path));
parser.nextToken();
fs = FeatureSet.fromJson(parser);
Uses a different pattern
Webmaps
map = new MapView(this,"http://www.arcgis.com/home/item.html?id=81d22...”,“name”,“password”
);
setContentView(map);
map = new MapView(this);map.addLayer(new ArcGISTiledMapServiceLayer(
"http://services.arcgisonline.com/ArcGIS/rest/services/...”));setContentView(map);
As compared to...
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()));
Rainald Suchan, Esri GermanySoftware Developer??????@esri.??Twitter ???
Andy Gup, Esri U.S.Tech Lead for Web APIs and AndroidEsri Developer Network [email protected] @agup