Building Applications with the ArcGIS Runtime SDK for Android

quaintmayoΚινητά – Ασύρματες Τεχνολογίες

10 Δεκ 2013 (πριν από 3 χρόνια και 10 μήνες)

913 εμφανίσεις

Building Applications with the
ArcGIS Runtime SDK for Android
Andy Gup
Who am I?


Andy Gup, Esri U.S.
Tech Lead for Web APIs, Android
Esri Developer Network
agup@esri.com
@agup
Agenda

Introduction

Runtime SDK
-
Tools and features

Maps & Layers

GPS

Tasks

Editing

Offline Capabilities

Summary
Assumptions
Basic understanding of the Google Android SDK
Understand how to create ArcGIS Android Project
Familiar with Eclipse
Some knowledge of Java
Who are you?
Maps Can Be Shared Across Devices
. . . Enhancing Access and Collaboration
One Map
Desktop
iOS
Windows
Phone
Android
Web Sites
Browsers
Online
Services
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

Download the SDK
http://esriurl.com/androidsdk

Project Configuration - res/layout/main.xml
<com.esri.android.map.MapView
android:id="@+id/map"
android:layout_height="fill_parent"
android:layout_width="fill_parent" />
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" />
Performance and the UI Thread

ALL UI work must be done on UI thread!


AsyncTask – easily run background thread

Handler() – bound to creation thread

ExecutorService – manage multiple AsyncTasks

FutureTask – cancellable asynchronous task

Thread
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.INITIALIZATION_FAILED == 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
}
}
}
Map Initialized Event Demo
Map touch events - MapOnTouchListener
Listening for map touch events
mMapView.setOnSingleTapListener(new OnSingleTapListener() {

public void onSingleTap(float arg0, float arg1) {
//TO-DO
}
});
Custom Event Event Listener
Class DragTouchListener extends MapOnTouchListener {


public DragTouchListener(Context arg0, MapView arg1) {
super(arg0, arg1);
}

public boolean onDragPointerMove(MotionEvent from, MotionEvent to) {

...

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 a default listener
//Remove default listener!
_mapView.setOnSingleTapListener(null);
Touch listeners demo
Microsoft Clip art
GPS and Device Location
_locationService = _mapView.getLocationService();
_locationService.setAutoPan(true);
_locationService.setAccuracyCircleOn(true);
_locationService.setLocationListener(new LocationListener() {
//TODO
});
_locationService.start();

GPS/Location restart
After application cold start, paused or view change.

Step 1: Verify Map + layer(s) are loaded

Step 2: Start the LocationManager and/or LocationService

Step 3: On location event autoCenter and/or draw graphic
Restart LocationService #1 – easy and quick
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 Runnable…


Step 1: unpause() map after onResume() event

Step 2: Implement a Runnable

Step 3: Implement a counter & check if map loaded

Step 4: Implement if count > X then fail gracefully

Step 5: start the Runnable



Example is in the EsriQuickStart on github

Location demo
Microsoft Clip art
Geo-Analysis

All ArcGIS Task samples are (currently) AsyncTask
-
Geocode
-
GeoProcessing
-
Identify
-
Query


Geoprocessing Example – Step 1
class ViewShedQuery extends AsyncTask<ArrayList<GPParameter>,
Void, GPParameter[]> {

GPParameter[] outParams = null;

@Override
protected void onPostExecute(GPParameter[] result) {
//TODO
}

@Override
protected GPParameter[] doInBackground(
ArrayList<GPParameter>... params1) {
//TODO
}
}
Geoprocessing Example – Step 2
@Override
protected GPParameter[] doInBackground(
ArrayList<GPParameter>... params1) {

...

try {
GPResultResource rr = gp.execute(params1[0]);
outParams = rr.getOutputParameters();
} catch (Exception e) {
e.printStackTrace();
}
return outParams;
}
Geoprocessing Example – Step 3

@Override
protected void onPostExecute(GPParameter[] result) {

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 Example – Step 4
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<GPParameter>();
params.add(gpf);
params.add(gpl);

new ViewShedQuery().execute(params); //ON THE UI THREAD!
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<FeatureEditResult[][]>() {

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


<!—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 – write JSON to SD Card
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
Webmaps
Uses a different pattern


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

setContentView(map);
map = (MapView) findViewById(R.id.map);
map.addLayer(new ArcGISTiledMapServiceLayer(
"http://services.arcgisonline.com/ArcGIS/rest/services/...”));
As compared to non-Webmaps…


ArcGIS for Android Application
Github
Android Quick Start Sample
Android GPS Tester
https://github.com/esri


Samples for this presentation:
https://github.com/andygup/getting-started-
android

GPSTester demo
Microsoft Clip art
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), DDMS and Logcat


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

DevSummit Android sessions include…
Agenda Search > Keyword > Android

Developing Mapping Apps with Android

Tue 4pm Pasadena/Venture/Sierra
Android User Group Meeting!

Wed 12pm Mesquite A
Implementing Analysis, Editing and Offline Apps w/ Android

Wed 4pm Pasadena/Venture/Sierra
iOS and Android: Let’s have a hug

Wed 5:30pm Catalina/Madera
Road ahead for Runtime SDKs

Thur 10am Primrose B


Who am I?


Andy Gup, Esri U.S.
Tech Lead for Web APIs, Android
Esri Developer Network
http://blog.andygup.net
agup@esri.com
@agup