You will learn: how to execute a SQL query for features from a service feature table and add those features to the map as graphics.

With the ArcGIS API for Java you can query a ServiceFeatureTable to retrieve a sub-set of data for your application. Features that come directly from a feature service are stored in a service feature table, which is created using the URL for the service and index position. In this scenario, the table is referenced but not added to the map as a feature layer. The query can contain a SQL where clause, a geometric feature, and a spatial relationship. After you create a QueryParameters object you can use it to retrieve data from a feature service table. When features are returned you can add them to your map as graphics or use them to perform other operations in your application.

In this lab you will create a SQL query to find all of the "Backbone" trails and then add them to the map.

Before you begin

Reuse the starter project

If you have not done the starter project lab, be sure to review it first so you are familiar with running the app.

In a new or empty folder, make a copy of the Create a starter app solution.

Complete or review lab Create a 2d map with a layer as you will repeat some of the parts here.

Steps

Update the project

  1. Open the settings.gradle file in an editor of your choice and change the rootProject.name value to query-a-feature-layer.

Imports and variable declarations

  1. Open the App.java file in src/main/java/com/arcgis/developers/labs. Then add the following with the existing imports.

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    
    import javafx.scene.control.Alert;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.data.FeatureQueryResult;
    import com.esri.arcgisruntime.data.QueryParameters;
    import com.esri.arcgisruntime.data.ServiceFeatureTable;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleRenderer;
    
  2. Add new private fields that will be used later.

    /* ** ADD ** */
    private final int hexRed = 0xFFFF0000;
    
    private GraphicsOverlay graphicsOverlay;
    /* ** ADD ** */
    private MapView mapView;
    
  3. More of the Los Angeles area will need to be within the map view. Change the levelOfDetail to 9 within the setupMap method.

    double latitude = 34.05293;
    double longitude = -118.24368;
    /* ** CHANGE ** */
    int levelOfDetail = 9;
    

Add a graphics overlay to the map view

  1. Add a new private method setupGraphicsOverlay that creates a graphics overlay and attaches it to the map view to render the graphics on the map. Each graphic must have a symbol assigned in order to be visible on the map.

    private void setupGraphicsOverlay() {
      if (mapView != null) {
        graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
      }
    }
    
  2. Set each graphic within the graphics overlay to display the same symbol.

    mapView.getGraphicsOverlays().add(graphicsOverlay);
    
    /* ** ADD * */
    SimpleLineSymbol symbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DASH_DOT, hexRed, 2.0f);
    graphicsOverlay.setRenderer(new SimpleRenderer(symbol));
    
  3. Call the method just created from the start method.

    setupMap();
    
    /* ** ADD ** */
    setupGraphicsOverlay();
    

Create and execute the query

  1. Add a method queryFeaturesFromTable that will query a ServiceFeatureTable for features. Start by loading the table using a service URL.

    private void queryFeaturesFromTable() {
      ServiceFeatureTable table = new ServiceFeatureTable(
          "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0");
      table.loadAsync();
    }
    
  2. Execute a query on the service feature table that finds all the features that has the word "backbone" within the TRL_NAME field.

    table.loadAsync();
    
    /* ** ADD ** */
    table.addDoneLoadingListener(() -> {
      QueryParameters query = new QueryParameters();
      query.setWhereClause("TRL_NAME like '%backbone%'");
      query.setReturnGeometry(true);
      ListenableFuture<FeatureQueryResult> tableQueryResult = table.queryFeaturesAsync(query);
    });
    
  3. Once the query is complete, take all features that were found and display them using the graphics overlay.

    ListenableFuture<FeatureQueryResult> tableQueryResult = table.queryFeaturesAsync(query);
    
    /* ** ADD ** */
    tableQueryResult.addDoneListener(() -> {
      try {
        List<Graphic> graphics = new ArrayList<>();
        FeatureQueryResult result = tableQueryResult.get();
        result.forEach(feature -> {
          graphics.add(new Graphic(feature.getGeometry()));
        });
        graphicsOverlay.getGraphics().addAll(graphics);
      } catch (ExecutionException | InterruptedException e) {
        new Alert(Alert.AlertType.ERROR, "Error querying Service Table:  " + e.getMessage()).show();
      }
    });
    
  4. Call the method just created.

    setupGraphicsOverlay();
    /* ** ADD ** */
    queryFeaturesFromTable();
    

Congratulations, you're done!

Your map should now display the Backbone trails near the Los Angeles area.

Challenge

Experiment with more SQL queries

Try changing the where clause to one of the ones listed below:

  LENGTH_MI < 5
  LENGTH_MI > 5
  ELEV_GAIN < 250
  ELEV_GAIN > 250
  USE_BIKE = 'Yes'
  USE_BIKE = 'No'
  USE_HIKE = 'Yes'
  USE_EQU = 'Yes'