Hello, here is the code that worked for me, I followed the feature-layer-show-attributes sample exactly, only implementing it for two layers instead of one:
public class MainActivity extends AppCompatActivity {
// existing map references
private MapView aMapView;
private LocationDisplay mLocationDisplay;
private Spinner mSpinner;
// request codes from Android
private int requestCode = 2;
String[] reqPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission
.ACCESS_COARSE_LOCATION};
// popups
private Callout aCallout;
private ServiceFeatureTable table0, table1;
// private static final String sTag = "Gesture";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get the Spinner from layout
mSpinner = (Spinner) findViewById(R.id.spinner);
// inflate MapView from layout
aMapView = (MapView) findViewById(mapView);
final ArcGISMap map = new ArcGISMap(Basemap.Type.DARK_GRAY_CANVAS_VECTOR, 48.6596, -113.7870, 9);
aMapView.setMap(map);
// get the callout that shows attributes
aCallout = aMapView.getCallout();
// layer 0, facilities
table0 = new ServiceFeatureTable(getResources().getString(R.string.layer0_url));
FeatureLayer featureLayer0 = new FeatureLayer(table0);
map.getOperationalLayers().add(featureLayer0);
// get the callout that shows attributes
aCallout = aMapView.getCallout();
// layer 1, trails
table1 = new ServiceFeatureTable(getResources().getString(R.string.layer1_url));
FeatureLayer featureLayer1 = new FeatureLayer(table1);
map.getOperationalLayers().add(featureLayer1);
// set an on touch listener to listen for click events
aMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, aMapView) {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// remove any existing callouts
if (aCallout.isShowing()) {
aCallout.dismiss();
}
// get the point that was clicked and convert it to a point in map coordinates
final Point clickPoint = aMapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())));
// create a selection tolerance
int tolerance = 10;
double mapTolerance = tolerance * aMapView.getUnitsPerDensityIndependentPixel();
// use tolerance to create an envelope to query
Envelope envelope = new Envelope(clickPoint.getX() - mapTolerance, clickPoint.getY() - mapTolerance, clickPoint.getX() + mapTolerance, clickPoint.getY() + mapTolerance, map.getSpatialReference());
QueryParameters query = new QueryParameters();
query.setGeometry(envelope);
// request all available attribute fields
final ListenableFuture<FeatureQueryResult> future_0 = table0.queryFeaturesAsync(query, ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
final ListenableFuture<FeatureQueryResult> future_1 = table1.queryFeaturesAsync(query, ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
//print all available attr fields in logcat
System.out.println(future_0.toString());
Log.d("FUTURE0", "see ^");
// example return: com.esri.arcgisruntime.data.ServiceFeatureTable$4@36c3a76
System.out.println(future_1.toString());
Log.d("FUTURE1", "see ^");
// add done loading listener to fire when the selection returns
future_0.addDoneListener(new Runnable() {
@Override
public void run() {
try {
//call get on the future to get the result
FeatureQueryResult result = future_0.get();
// create an Iterator
Iterator<Feature> iterator = result.iterator();
// create a TextView to display field values
TextView calloutContent = new TextView(getApplicationContext());
calloutContent.setTextColor(Color.BLACK);
calloutContent.setSingleLine(false);
calloutContent.setVerticalScrollBarEnabled(true);
calloutContent.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
calloutContent.setMovementMethod(new ScrollingMovementMethod());
calloutContent.setLines(5);
// cycle through selections
int counter = 0;
Feature feature;
while (iterator.hasNext()) {
feature = iterator.next();
// create a Map of all available attributes as name value pairs
Map<String, Object> attr = feature.getAttributes();
Set<String> keys = attr.keySet();
for (String key : keys) {
Object value = attr.get(key);
// format observed field value as date
if (value instanceof GregorianCalendar) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
value = simpleDateFormat.format(((GregorianCalendar) value).getTime());
}
//don't append the null ones
if(value.toString() != null | value.toString() != "" | value.toString() != "null") {
// append name value pairs to TextView
calloutContent.append(key + " | " + value + "\n");
}
}
counter++;
// center the mapview on selected feature
Envelope envelope = feature.getGeometry().getExtent();
aMapView.setViewpointGeometryAsync(envelope, 200);
// show CallOut
aCallout.setLocation(clickPoint);
aCallout.setContent(calloutContent);
aCallout.show();
}
} catch (Exception e) {
Log.e(getResources().getString(R.string.app_name), "Select feature failed: " + e.getMessage());
}
}
});
// add done loading listener to fire when the selection returns
future_1.addDoneListener(new Runnable() {
@Override
public void run() {
try {
//call get on the future to get the result
FeatureQueryResult result = future_1.get();
// create an Iterator
Iterator<Feature> iterator = result.iterator();
// create a TextView to display field values
TextView calloutContent = new TextView(getApplicationContext());
calloutContent.setTextColor(Color.BLACK);
calloutContent.setSingleLine(false);
calloutContent.setVerticalScrollBarEnabled(true);
calloutContent.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
calloutContent.setMovementMethod(new ScrollingMovementMethod());
calloutContent.setLines(5);
// cycle through selections
int counter = 0;
Feature feature;
while (iterator.hasNext()) {
feature = iterator.next();
// create a Map of all available attributes as name value pairs
Map<String, Object> attr = feature.getAttributes();
Set<String> keys = attr.keySet();
for (String key : keys) {
Object value = attr.get(key);
// format observed field value as date
if (value instanceof GregorianCalendar) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
value = simpleDateFormat.format(((GregorianCalendar) value).getTime());
}
//don't append the null ones
if(value.toString() != null | value.toString() != "" | value.toString() != "null") {
// append name value pairs to TextView
calloutContent.append(key + " | " + value + "\n");
}
}
counter++;
// center the mapview on selected feature
Envelope envelope = feature.getGeometry().getExtent();
aMapView.setViewpointGeometryAsync(envelope, 200);
// show CallOut
aCallout.setLocation(clickPoint);
aCallout.setContent(calloutContent);
aCallout.show();
}
} catch (Exception e) {
Log.e(getResources().getString(R.string.app_name), "Select feature failed: " + e.getMessage());
}
}
});
return super.onSingleTapConfirmed(e);
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Location permission was granted. This would have been triggered in response to failing to start the
// LocationDisplay, so try starting this again.
mLocationDisplay.startAsync();
} else {
// If permission was denied, show toast to inform user what was chosen. If LocationDisplay is started again,
// request permission UX will be shown again, option should be shown to allow never showing the UX again.
// Alternative would be to disable functionality so request is not shown again.
Toast.makeText(MainActivity.this, getResources().getString(R.string.location_permission_denied), Toast
.LENGTH_SHORT).show();
// Update UI to reflect that the location display did not actually start
mSpinner.setSelection(0, true);
}
}
@Override
protected void onPause() {
super.onPause();
aMapView.pause();
}
@Override
protected void onResume() {
super.onResume();
aMapView.resume();
}
}