AnsweredAssumed Answered

How to get a listener for many Feature Layers in ArcGIS Android?

Question asked by durand.gael on Sep 13, 2017
Latest reply on Sep 18, 2017 by durand.gael

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;
    }
}

Outcomes