I have two Feature Layers added into a Map that I can see when I display the MapView. However, it's only the last added Feature Layer that can be processed by the Touch Listener. I cannot figure out how to make all Features Layers taken into account by the Touch Listener. My goal is to differentiate a click on a CARTO_ETARE's feature from a click on a CARTO_PT_EAU's one. Any help would be appreciated. import android.Manifest; import android.content.pm.PackageManager; import android.graphics.Color; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; import com.esri.arcgisruntime.concurrent.ListenableFuture; import com.esri.arcgisruntime.data.Feature; import com.esri.arcgisruntime.data.FeatureQueryResult; import com.esri.arcgisruntime.data.Geodatabase; import com.esri.arcgisruntime.data.GeodatabaseFeatureTable; import com.esri.arcgisruntime.data.QueryParameters; import com.esri.arcgisruntime.geometry.Envelope; import com.esri.arcgisruntime.geometry.Point; import com.esri.arcgisruntime.layers.FeatureLayer; import com.esri.arcgisruntime.mapping.ArcGISMap; import com.esri.arcgisruntime.mapping.Basemap; import com.esri.arcgisruntime.mapping.view.DefaultMapViewOnTouchListener; import com.esri.arcgisruntime.mapping.view.GraphicsOverlay; import com.esri.arcgisruntime.mapping.view.MapView; import com.google.android.gms.tasks.OnCompleteListener; import com.sigpau.sigpau.R; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import static com.sigpau.sigpau.R.id.mapView; // TIP: "Invalidate caches and Restart" in Android Studio in case of debugger unreachable public class MainActivityDemo extends AppCompatActivity implements View.OnClickListener, OnCompleteListener<Void> { private MapView mMapView; private static File extStorDir; private static String extSDCardDirName; private static String geodbFilename; private static String mGeoDb; private Geodatabase mGeodatabase; // define permission to request private final String[] reqPermission = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; private ArcGISMap mMap; private FeatureLayer mFeatureLayer; private ListenableFuture<FeatureQueryResult> mFuture; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // inflate MapView from layout mMapView = (MapView) findViewById(mapView); // create a map with the streets basemap mMap = new ArcGISMap(Basemap.Type.TOPOGRAPHIC, 48.1119800, -1.6742900, 14); //set an initial viewpoint // set the map to be displayed in the MapView mMapView.setMap(mMap); // create the path to local data extStorDir = Environment.getExternalStorageDirectory(); extSDCardDirName = this.getResources().getString(R.string.config_data_sdcard_offline_dir); geodbFilename = this.getResources().getString(R.string.config_geodb_name); // full path to data mGeoDb = createGeoDbFilePath(); ActivityCompat.requestPermissions(MainActivityDemo.this, reqPermission, 2); } /** * Handle the permissions request response */ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // create a new Geodatabase from local path mGeodatabase = new Geodatabase(mGeoDb); // load the geodatabase mGeodatabase.loadAsync(); // add feature layer from geodatabase to the ArcGISMap mGeodatabase.addDoneLoadingListener(new Runnable() { @Override public void run() { for (GeodatabaseFeatureTable geoDbTable : mGeodatabase.getGeodatabaseFeatureTables()){ ArrayList<String> list_of_tables = new ArrayList<String>(); list_of_tables.add("CARTO_ETARE"); list_of_tables.add("CARTO_PT_EAU"); Set<String> set = new HashSet<String>(list_of_tables); if (set.contains(geoDbTable.getTableName())) { mFeatureLayer = new FeatureLayer(geoDbTable); mFeatureLayer.setSelectionColor(Color.YELLOW); mFeatureLayer.setLabelsEnabled(true); mFeatureLayer.setSelectionWidth(10); //featureLayer.selectFeatures(); mMap.getOperationalLayers().add(mFeatureLayer); mMapView.setMap(mMap); // set an on touch listener to listen for click events mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(MainActivityDemo.this, mMapView) { @Override public boolean onSingleTapConfirmed(MotionEvent e) { // get the point that was clicked and convert it to a point in map coordinates Point clickPoint = mMapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY()))); int tolerance = 10; double mapTolerance = tolerance * mMapView.getUnitsPerDensityIndependentPixel(); // create objects required to do a selection with a query Envelope envelope = new Envelope(clickPoint.getX() - mapTolerance, clickPoint.getY() - mapTolerance, clickPoint.getX() + mapTolerance, clickPoint.getY() + mapTolerance, mMap.getSpatialReference()); QueryParameters query = new QueryParameters(); query.setGeometry(envelope); // call select features mFuture = mFeatureLayer.selectFeaturesAsync(query, FeatureLayer.SelectionMode.ADD); // add done loading listener to fire when the selection returns mFuture.addDoneListener(new Runnable() { @Override public void run() { try { //call get on the future to get the result FeatureQueryResult result = mFuture.get(); // create an Iterator Iterator<Feature> iterator = result.iterator(); Feature feature; while (iterator.hasNext()) { feature = iterator.next(); Map<String, Object> attributes = feature.getAttributes(); if(feature.getFeatureTable().getTableName().equals("CARTO_PT_EAU")) { Toast.makeText(getApplicationContext(), Long.toString((Long)attributes.get("ID_PT_EAU")), Toast.LENGTH_SHORT).show(); } else if(feature.getFeatureTable().getTableName().equals("CARTO_ETARE")) { Toast.makeText(getApplicationContext(), Long.toString((Long)attributes.get("CARTO_ETARE")), Toast.LENGTH_SHORT).show(); } } } catch (Exception e) { Log.e(getResources().getString(R.string.app_name), "Select feature failed: " + e.getMessage()); } } }); return super.onSingleTapConfirmed(e); } }); } } } }); } else { // report to user that permission was denied Toast.makeText(MainActivityDemo.this, getResources().getString(R.string.location_permission_denied), Toast.LENGTH_SHORT).show(); } } /** * Create the mobile geodatabase file location and name structure */ private static String createGeoDbFilePath() { return extStorDir.getAbsolutePath() + File.separator + extSDCardDirName + File.separator + geodbFilename; } } |
Solved! Go to Solution.
Hi durand.gael,
The point passed to the identifyLayerAsync method is a android.graphic.point so you can pass in the screen location that was touched to do the identify. It takes care of all the conversion to a localized point for you. This allows you to quickly implement the touch to identify rather than having to go through the process of manually converting the point.
Can you post your code so its on seperate lines? It is a little hard to read here...
The update is done.
Sorry for the long line...
Is there a reason that you are not using the identifyLayerAync method on the mapview?
This should return an identifyLayerResult which you can use to get all the identified features with.
Hi,
Thanks for the idea, but it's still not working because the Point passed to identifyLayersAsync is recognized as an android.graphics.point. That's weird.
What I've done so far:
mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(MainActivity.this, mMapView) { @Override public boolean onSingleTapConfirmed(MotionEvent e) { mInfoButton.setVisibility(View.GONE); mContactButton.setVisibility(View.GONE); mPlanButton.setVisibility(View.GONE); Point gps = new Point(-1.640235, 48.127568, SpatialReferences.getWgs84()); final ListenableFuture<List<IdentifyLayerResult>> identifyFuture = mMapView.identifyLayersAsync(gps, 20, false, 25); // add a listener to the future identifyFuture.addDoneListener(new Runnable() { @Override public void run() { try { // get the identify results from the future - returns when the operation is complete List<IdentifyLayerResult> identifyLayersResults = identifyFuture.get(); // iterate all the layers in the identify result for (IdentifyLayerResult identifyLayerResult : identifyLayersResults) { // iterate each result in each identified layer, and check for Feature results for (GeoElement identifiedElement : identifyLayerResult.getElements()) { if (identifiedElement instanceof Feature) { } } } } catch (InterruptedException | ExecutionException ex) { Log.e(getResources().getString(R.string.app_name), ex.getMessage()); } } });
Hi durand.gael,
The point passed to the identifyLayerAsync method is a android.graphic.point so you can pass in the screen location that was touched to do the identify. It takes care of all the conversion to a localized point for you. This allows you to quickly implement the touch to identify rather than having to go through the process of manually converting the point.
Hi Alexander,
Thanks for the answer.
This is how I create the point from the screen touch:
final ListenableFuture<List<IdentifyLayerResult>> identifyFuture = mMapView.identifyLayersAsync(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())), 20, false, 25);