[Java for Android App Development] losaruka:
Hi,

I want do develop an Android App with the SDK 'ArcGIS for Android'. There I have downloaded two Samples: PopupInWebMapForViewing an Routing. And thats my target: I want these two samples in one Projekt or in one .java-File.

I'm done this, but the App doesn't work on my Smartphone. It only shows up, that the App has stopped. If I comment out all the stuff from Routing, it will work. And if I uncomment all expect of the Layers from the Routing, it will also work. The Routing will be activate by long clicking on the map. But in this case, the App will crash.

I don't know much about java but its a projekt for the university. I hope that someone can help me.

Thank you all very much in advance for your help and sorry for my bad english.

Here's the code:

public class BAAppActivity extends Activity {
MapView map;

////////////////////////////// Popup /////////////////////////////
PopupContainer popupContainer;
PopupDialog popupDialog;
ProgressDialog progressDialog;
AtomicInteger count;

////////////////////////////// Routing /////////////////////////////
ArcGISTiledMapServiceLayer tileLayer;
GraphicsLayer routeLayer, hiddenSegmentsLayer;
// Symbol used to make route segments "invisible"
SimpleLineSymbol segmentHider = new SimpleLineSymbol(Color.WHITE, 5);
// Symbol used to highlight route segments
SimpleLineSymbol segmentShower = new SimpleLineSymbol(Color.RED, 5);
// Label showing the current direction, time, and length
TextView directionsLabel;
// List of the directions for the current route (used for the ListActivity)
ArrayList<String> curDirections = null;
// Current route, route summary, and gps location
Route curRoute = null;
String routeSummary = null;
Point mLocation = null;
// Global results variable for calculating route on separate thread
RoutingResult mResults = null;
// Variable to hold server exception to show to user
Exception mException = null;
// Handler for processing the results
final Handler mHandler = new Handler();
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateUI();
}
};

////////////////////////////// Routing /////////////////////////////
// Progress dialog to show when route is being calculated
ProgressDialog dialog;
// Spatial references used for projecting points
final SpatialReference wm = SpatialReference.create(102100);
final SpatialReference egs = SpatialReference.create(4326);
// Index of the currently selected route segment (-1 = no selection)
int selectedSegmentID = -1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
////////////////////////////// Routing /////////////////////////////
setContentView(R.layout.main);

////////////////////////////// Popup /////////////////////////////
// Lade die Basemap von ArcGIS online.
map = new MapView(this, "some map", "", "");
setContentView(map);

////////////////////////////// Routing /////////////////////////////
// Retrieve the map and initial extent from XML layout
map = (MapView) findViewById(R.id.map);
// Add tiled layer to MapView
tileLayer = new ArcGISTiledMapServiceLayer(
"Layer");
map.addLayer(tileLayer);

// Add the route graphic layer (shows the full route)
routeLayer = new GraphicsLayer();
map.addLayer(routeLayer);

// Add the hidden segments layer (for highlighting route segments)
hiddenSegmentsLayer = new GraphicsLayer();
map.addLayer(hiddenSegmentsLayer);

// Make the segmentHider symbol "invisible"
segmentHider.setAlpha(1);

// Get the location service and start reading location. Don't auto-pan
// to center our position
LocationService ls = map.getLocationService();
ls.setLocationListener(new MyLocationListener());
ls.start();
ls.setAutoPan(false);

// Set the directionsLabel with initial instructions.
directionsLabel = (TextView) findViewById(R.id.directionsLabel);
directionsLabel.setText(getString(R.string.route_label));

/**
* On single clicking the directions label, start a ListActivity to show
* the list of all directions for this route. Selecting one of those
* items will return to the map and highlight that segment.
*
*/
directionsLabel.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
if (curDirections == null)
return;
Intent i = new Intent(getApplicationContext(),
ShowDirections.class);
i.putStringArrayListExtra("directions", curDirections);
startActivityForResult(i, 1);
}

});

/**
* On long clicking the directions label, removes the current route and
* resets all affiliated variables.
*
*/
directionsLabel.setOnLongClickListener(new OnLongClickListener() {

public boolean onLongClick(View v) {
routeLayer.removeAll();
hiddenSegmentsLayer.removeAll();
curRoute = null;
curDirections = null;
directionsLabel.setText(getString(R.string.route_label));
return true;
}

});

////////////////////////////// Popup /////////////////////////////
// Tippe auf die Karte und öffne ein Popup für das selektierte Feature.
map.setOnSingleTapListener(new OnSingleTapListener() {
private static final long serialVersionUID = 1L;

public void onSingleTap(float x, float y) {
////////////////////////////// Routing /////////////////////////////
// Get all the graphics within 20 pixels the click
int[] indexes = hiddenSegmentsLayer.getGraphicIDs(x, y, 20);
// Hide the currently selected segment
hiddenSegmentsLayer.updateGraphic(selectedSegmentID,
segmentHider);

if (indexes.length < 1) {
// If no segments were found but there is currently a route,
// zoom to the extent of the full route
if (curRoute != null) {
map.setExtent(curRoute.getEnvelope(), 250);
directionsLabel.setText(routeSummary);
}
return;
}
// Otherwise update our currently selected segment
selectedSegmentID = indexes[0];
Graphic selected = hiddenSegmentsLayer
.getGraphic(selectedSegmentID);
// Highlight it on the map
hiddenSegmentsLayer.updateGraphic(selectedSegmentID,
segmentShower);
String direction = ((String) selected.getAttributeValue("text"));
double time = ((Double) selected.getAttributeValue("time"))
.doubleValue();
double length = ((Double) selected.getAttributeValue("length"))
.doubleValue();
// Update the label with this direction's information
String label = String.format(
"%s%nTime: %.1f minutes, Length: %.1f miles",
direction, time, length);
directionsLabel.setText(label);
// Zoom to the extent of that segment
map.setExtent(selected.getGeometry(), 50);

////////////////////////////// Popup /////////////////////////////
if (map.isLoaded()) {
// PopupContainer realisieren.
popupContainer = new PopupContainer(map);
int id = popupContainer.hashCode();
popupDialog = null;
// spinner (Auswahl) anzeigen.
if (progressDialog == null || !progressDialog.isShowing())
progressDialog = ProgressDialog.show(map.getContext(), "", "Rufe Informationen ab...");

// Loop durch jeden Layer in der Basemap.
int tolerance = 20;
Envelope env = new Envelope(map.toMapPoint(x, y), 20 * map.getResolution(), 20 * map.getResolution());
Layer[] layers = map.getLayers();
count = new AtomicInteger();
for (Layer layer : layers) {
// Wenn der Layer noch nicht geladen wurde oder unsichtbar ist, nichts machen.
if (!layer.isInitialized() || !layer.isVisible())
continue;

if (layer instanceof ArcGISFeatureLayer) {
// Frage den FeatureLayer ab und zeige die Popups.
ArcGISFeatureLayer featureLayer = (ArcGISFeatureLayer) layer;
if (featureLayer.getPopupInfo() != null) {
// Frage den FeatureLayer ab, welcher mit den Popupdefinitionen verknüpft ist.
count.incrementAndGet();
new RunQueryFeatureLayerTask(x, y, tolerance, id).execute(featureLayer);
}
}
else if (layer instanceof ArcGISDynamicMapServiceLayer) {
// Frage den DynamicLayer ab und zeige die Popups.
ArcGISDynamicMapServiceLayer dynamicLayer = (ArcGISDynamicMapServiceLayer) layer;
// Empfange Layerinfos für jeden Sub-Layer des dynamic map service layer.
ArcGISLayerInfo[] layerinfos = dynamicLayer.getAllLayers();
if (layerinfos == null)
continue;

// Loop durch jeden Sub-Layer.
for (ArcGISLayerInfo layerInfo : layerinfos) {
// erhalte PopupInfo für die Sub-Layer.
PopupInfo popupInfo = dynamicLayer.getPopupInfo(layerInfo.getId());
// Überspringe Sub-Layer, welche keine Popup-Definitionen enthalten.
if (popupInfo == null) {
continue;
}
// Überprüfe ob der Sub-Layer sichtbar ist.
ArcGISLayerInfo info = layerInfo;
while (info != null && info.isVisible()) {
info = info.getParentLayer();
}
// Überspringe unsichtbare Sub-Layer.
if (info != null && ! info.isVisible()) {
continue;
};

// Überprüfe ob der Sub-Layer innerhalb des Skalenbereichs ist.
double maxScale = (layerInfo.getMaxScale() != 0) ? layerInfo.getMaxScale():popupInfo.getMaxScale();
double minScale = (layerInfo.getMinScale() != 0) ? layerInfo.getMinScale():popupInfo.getMinScale();

if ((maxScale == 0 || map.getScale() > maxScale) && (minScale == 0 || map.getScale() < minScale)) {
// Frage die Sub-Layer ab, welche mit den Popup-Definitionen verknüpft sind und sichtbar sind und im Skalenbereich liegen.
count.incrementAndGet();
new RunQueryDynamicLayerTask(env, layer, layerInfo.getId(), dynamicLayer.getSpatialReference(), id).execute(dynamicLayer.getUrl() + "/" + layerInfo.getId());
}
}
}
}
}
}
});

////////////////////////////// Routing /////////////////////////////
/**
* On long pressing the map view, route from our current location to the
* pressed location.
*
*/
map.setOnLongPressListener(new OnLongPressListener() {

private static final long serialVersionUID = 1L;

public void onLongPress(final float x, final float y) {

// Clear the graphics and empty the directions list
routeLayer.removeAll();
hiddenSegmentsLayer.removeAll();
curDirections = new ArrayList<String>();
mResults = null;

// retrieve the user clicked location
final Point loc = map.toMapPoint(x, y);

// Show that the route is calculating
dialog = ProgressDialog.show(BAAppActivity.this, "",
"Calculating route...", true);
// Spawn the request off in a new thread to keep UI responsive
Thread t = new Thread() {
@Override
public void run() {
try {
// Start building up routing parameters
RoutingParameters rp = new RoutingParameters();
NAFeaturesAsFeature rfaf = new NAFeaturesAsFeature();
// Convert point to EGS (decimal degrees)
Point p = (Point) GeometryEngine.project(loc, wm,
egs);
// Create the stop points (start at our location, go
// to pressed location)
StopGraphic point1 = new StopGraphic(mLocation);
StopGraphic point2 = new StopGraphic(p);
rfaf.setFeatures(new Graphic[] { point1, point2 });
rfaf.setCompressedRequest(true);
rp.setStops(rfaf);
// Set the routing service output SR to our map
// service's SR
rp.setOutSpatialReference(wm);

// Create a new routing task pointing to an
// NAService (null credentials -> free service)
RoutingTask rt = new RoutingTask(
"RoutingTask",
null);

// Solve the route and use the results to update UI
// when received
mResults = rt.solve(rp);
mHandler.post(mUpdateResults);
} catch (Exception e) {
mException = e;
mHandler.post(mUpdateResults);
}
}
};
// Start the operation
t.start();
}
});
}

////////////////////////////// Popup /////////////////////////////
private void createPopupViews(Graphic[] graphics, final int id) {
if (id != popupContainer.hashCode()) {
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}

if (popupDialog == null) {
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();

// Mache einen Dialog für die popups und zeige ihn.
popupDialog = new PopupDialog(map.getContext(), popupContainer);
popupDialog.show();
}
}

// Frage den Feature Layer durch einen Trefferüberprüfung ab.
private class RunQueryFeatureLayerTask extends AsyncTask<ArcGISFeatureLayer, Void, Graphic[]> {

private int tolerance;
private float x;
private float y;
private ArcGISFeatureLayer featureLayer;
private int id;

public RunQueryFeatureLayerTask(float x, float y, int tolerance, int id) {
super();
this.x = x;
this.y = y;
this.tolerance = tolerance;
this.id = id;
}

@Override
protected Graphic [] doInBackground(ArcGISFeatureLayer...params) {
for (ArcGISFeatureLayer featureLayer : params) {
this.featureLayer = featureLayer;
// Grafik-IDs in der Nähe der Punkte abrufen.
int[] ids = featureLayer.getGraphicIDs(x, y, tolerance);
if (ids != null && ids.length > 0) {
ArrayList<Graphic> graphics = new ArrayList<Graphic>();
for (int id : ids) {
// Grafiken basierend auf den IDs erhalten.
Graphic g = featureLayer.getGraphic(id);
if (g == null)
continue;
graphics.add(g);
}
// Liefert ein Array von Grafiken in der Nähe des Punktes.
return graphics.toArray(new Graphic[0]);
}
}
return null;
}

@Override
protected void onPostExecute(Graphic[] graphics) {
count.decrementAndGet();
if (graphics == null || graphics.length == 0) {
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}

for (Graphic gr : graphics) {
Popup popup = featureLayer.createPopup(map, 0, gr);
popupContainer.addPopup(popup);
}
createPopupViews(graphics, id);
}

}

// Frage den Dynamic Map Service Layer mit QueryTask ab.
private class RunQueryDynamicLayerTask extends AsyncTask<String, Void, FeatureSet> {
private Envelope env;
private SpatialReference sr;
private int id;
private Layer layer;
private int subLayerId;

public RunQueryDynamicLayerTask(Envelope env, Layer layer, int subLayerId, SpatialReference sr, int id) {
super();
this.env = env;
this.sr = sr;
this.id = id;
this.layer = layer;
this.subLayerId = subLayerId;
}

@Override
protected FeatureSet doInBackground(String... urls) {
for (String url : urls) {
// Erhalte Grafiken innerhalb der Hülle.
Query query = new Query();
query.setInSpatialReference(sr);
query.setOutSpatialReference(sr);
query.setGeometry(env);
query.setMaxFeatures(10);
query.setOutFields(new String[] { "*" });

QueryTask queryTask = new QueryTask(url);
try {
FeatureSet results = queryTask.execute(query);
return results;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

@Override
protected void onPostExecute(final FeatureSet result) {
count.decrementAndGet();
if (result == null) {
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}
Graphic[] graphics = result.getGraphics();
if (graphics == null || graphics.length == 0) {
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}
// Überprüfen, ob die angeforderte PopupContainer-Id identisch mit dem aktuellen PopupContainer ist.
// Andernfalls verlasse die veralteten Abfragen.
if (id != popupContainer.hashCode()) {
// Spinner verwerfen.
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}
PopupInfo popupInfo = layer.getPopupInfo(subLayerId);
if (popupInfo == null) {
// Spinner verwerfen.
if (progressDialog != null && progressDialog.isShowing() && count.intValue() == 0)
progressDialog.dismiss();

return;
}

for (Graphic gr : graphics) {
Popup popup = layer.createPopup(map, subLayerId, gr);
popupContainer.addPopup(popup);

}
createPopupViews(graphics, id);

}
}

// Ein angepasster Vollbild-Dialog.
private class PopupDialog extends Dialog {
private PopupContainer popupContainer;

public PopupDialog(Context context, PopupContainer popupContainer) {
super(context, android.R.style.Theme);
this.popupContainer = popupContainer;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
LinearLayout layout = new LinearLayout(getContext());
layout.addView(popupContainer.getPopupContainerView(), LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
setContentView(layout, params);
}

}

////////////////////////////// Routing /////////////////////////////
/**
* Updates the UI after a successful rest response has been received.
*/
void updateUI() {
dialog.dismiss();
if (mResults == null) {
Toast.makeText(BAAppActivity.this, mException.toString(),
Toast.LENGTH_LONG).show();
return;
}
curRoute = mResults.getRoutes().get(0);
// Symbols for the route and the destination (blue line, checker flag)
SimpleLineSymbol routeSymbol = new SimpleLineSymbol(Color.BLUE, 3);
PictureMarkerSymbol destinationSymbol = new PictureMarkerSymbol(
getResources().getDrawable(R.drawable.flag_finish));

// Add all the route segments with their relevant information to the
// hiddenSegmentsLayer, and add the direction information to the list
// of directions
for (RoutingDirection rd : curRoute.getRoutingDirections()) {
HashMap<String, Object> attribs = new HashMap<String, Object>();
attribs.put("text", rd.getText());
attribs.put("time", Double.valueOf(rd.getTime()));
attribs.put("length", Double.valueOf(rd.getLength()));
curDirections.add(String.format(
"%s%nTime: %.1f minutes, Length: %.1f miles", rd.getText(),
rd.getTime(), rd.getLength()));
hiddenSegmentsLayer.addGraphic(new Graphic(rd.getGeometry(),
segmentHider, attribs, null));
}
// Reset the selected segment
selectedSegmentID = -1;

// Add the full route graphic and destination graphic to the routeLayer
Graphic routeGraphic = new Graphic(curRoute.getRoute().getGeometry(),
routeSymbol);
Graphic endGraphic = new Graphic(
((Polyline) routeGraphic.getGeometry()).getPoint(((Polyline) routeGraphic
.getGeometry()).getPointCount() - 1), destinationSymbol);
routeLayer.addGraphics(new Graphic[] { routeGraphic, endGraphic });
// Get the full route summary and set it as our current label
routeSummary = String.format(
"%s%nTotal time: %.1f minutes, length: %.1f miles",
curRoute.getRouteName(), curRoute.getTotalTime(),
curRoute.getTotalLength());
directionsLabel.setText(routeSummary);
// Zoom to the extent of the entire route with a padding
map.setExtent(curRoute.getEnvelope(), 250);
}

/**
* On returning from the list of directions, highlight and zoom to the
* segment that was selected from the list. (Activity simply resumes if the
* back button was hit instead).
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Response from directions list view
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
String direction = data.getStringExtra("returnedDirection");
if (direction == null)
return;
// Look for the graphic that corresponds to this direction
for (int index : hiddenSegmentsLayer.getGraphicIDs()) {
Graphic g = hiddenSegmentsLayer.getGraphic(index);
if (direction
.contains((String) g.getAttributeValue("text"))) {
// When found, hide the currently selected, show the new
// selection
hiddenSegmentsLayer.updateGraphic(selectedSegmentID,
segmentHider);
hiddenSegmentsLayer.updateGraphic(index, segmentShower);
selectedSegmentID = index;
// Update label with information for that direction
directionsLabel.setText(direction);
// Zoom to the extent of that segment
map.setExtent(
hiddenSegmentsLayer.getGraphic(
selectedSegmentID).getGeometry(), 50);
break;
}
}
}
}
}

private class MyLocationListener implements LocationListener {

public MyLocationListener() {
super();
}

/**
* If location changes, update our current location. If being found for
* the first time, zoom to our current position with a resolution of 20
*/
public void onLocationChanged(Location loc) {
if (loc == null)
return;
boolean zoomToMe = (mLocation == null) ? true : false;
mLocation = new Point(loc.getLongitude(), loc.getLatitude());
if (zoomToMe) {
Point p = (Point) GeometryEngine.project(mLocation, egs, wm);
map.zoomToResolution(p, 20.0);
}
}

public void onProviderDisabled(String provider) {
Toast.makeText(getApplicationContext(), "GPS Disabled",
Toast.LENGTH_SHORT).show();
}

public void onProviderEnabled(String provider) {
Toast.makeText(getApplicationContext(), "GPS Enabled",
Toast.LENGTH_SHORT).show();
}

public void onStatusChanged(String provider, int status, Bundle extras) {
}

}

@Override
protected void onPause() {
super.onPause();
map.pause();
}

@Override
protected void onResume() {
super.onResume();
map.unpause();
}
}

I know, it's a long code. Maybe someone find an error or something else. :)

Best regards

losaruka