Feature layer query

View inJavaKotlin
View on GitHub
Sample viewer app

Find features in a feature table which match an SQL query.

Image of feature layer query

Use case

Query expressions can be used in ArcGIS to select a subset of features from a feature table. This is most useful in large or complicated data sets. A possible use case might be on a feature table marking the location of street furniture through a city. A user may wish to query by a TYPE column to return "benches". In this sample, we query a U.S. state by STATE_NAME from a feature table containing all U.S. states.

How to use the sample

Input the name of a U.S. state into the text field. When you tap "GO", a query is performed and the matching features are highlighted or an error is returned.

How it works

  1. Create a ServiceFeatureTable using the URL of a feature service.
  2. Create a QueryParameters with a where clause specified using setWhereClause().
  3. Perform the query using queryFeaturesAsync(query) on the service feature table.
  4. When complete, the query will return a FeatureQueryResult which can be iterated over to get the matching features.

About the data

This sample uses U.S. State polygon features from the USA 2016 Daytime Population feature service.

Relevant API

  • FeatureLayer
  • FeatureQueryResult
  • QueryParameters
  • ServiceFeatureTable


Search and Query

Sample Code

/* Copyright 2016 ESRI
 * All rights reserved under the copyright laws of the United States
 * and applicable international laws, treaties, and conventions.
 * You may freely redistribute and use this sample code, with or
 * without modification, provided you include the original copyright
 * notice and use restrictions.
 * See the Sample code usage restrictions document for further information.

package com.esri.arcgisruntime.sample.featurelayerquery;

import java.util.Iterator;

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.SpatialReferences;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.BasemapStyle;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;

public class MainActivity extends AppCompatActivity {

  private static final String TAG = MainActivity.class.getSimpleName();

  private MapView mMapView;
  private ServiceFeatureTable mServiceFeatureTable;
  private FeatureLayer mFeatureLayer;

  protected void onCreate(Bundle savedInstanceState) {

    // authentication with an API key or named user is required to access basemaps and other
    // location services

    // get reference to map view
    mMapView = findViewById(R.id.mapView);
    // create a map with the topographic basemap
    final ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_TOPOGRAPHIC);
    // set the map to the map view

    // create a service feature table and a feature layer from it
    mServiceFeatureTable = new ServiceFeatureTable(getString(R.string.us_daytime_population_url));
    // create the feature layer using the service feature table
    mFeatureLayer = new FeatureLayer(mServiceFeatureTable);

    //override the renderer
    SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.BLACK, 1);
    SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.YELLOW, lineSymbol);
    mFeatureLayer.setRenderer(new SimpleRenderer(fillSymbol));

    // add the layer to the map

    // zoom to a view point of the USA
    mMapView.setViewpointCenterAsync(new Point(-11000000, 5000000, SpatialReferences.getWebMercator()), 100000000);

   * Handle the search intent from the search widget
  protected void onNewIntent(Intent intent) {
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
      String searchString = intent.getStringExtra(SearchManager.QUERY);

  private void searchForState(final String searchString) {
    // clear any previous selections
    // create objects required to do a selection with a query
    QueryParameters query = new QueryParameters();
    // make search case insensitive
    query.setWhereClause("upper(STATE_NAME) LIKE '%" + searchString.toUpperCase() + "%'");
    // call select features
    final ListenableFuture<FeatureQueryResult> future = mServiceFeatureTable.queryFeaturesAsync(query);
    // add done loading listener to fire when the selection returns
    future.addDoneListener(() -> {
      try {
        // call get on the future to get the result
        FeatureQueryResult result = future.get();
        // check there are some results
        Iterator<Feature> resultIterator = result.iterator();
        if (resultIterator.hasNext()) {
          // get the extent of the first feature in the result to zoom to
          Feature feature = resultIterator.next();
          Envelope envelope = feature.getGeometry().getExtent();
          mMapView.setViewpointGeometryAsync(envelope, 10);
          // select the feature
        } else {
          Toast.makeText(this, "No states found with name: " + searchString, Toast.LENGTH_LONG).show();
      } catch (Exception e) {
        String error = "Feature search failed for: " + searchString + ". Error: " + e.getMessage();
        Toast.makeText(this, error, Toast.LENGTH_LONG).show();
        Log.e(TAG, error);

  public boolean onCreateOptionsMenu(Menu menu) {
    // inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    // get the SearchView and set the searchable configuration
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
    // assumes current activity is the searchable activity
    return true;

  protected void onPause() {

  protected void onResume() {

  @Override protected void onDestroy() {