Query Feature Service Table

This sample shows how you can create a GeodatabaseFeatureServiceTable, initialize it from a feature service, create a FeatureLayer based on that table, and also query the table. Features found by the query are then selected in the map.

To perform a query, select values in the two spinners, and then press the OK button.


  • GeodatabaseFeatureServiceTable
  • FeatureLayer, including queryFeatures, clearSelection, and selectFeature methods
  • CodedValueDomain

Sample Design

In this app, the FeatureServiceTableQueryActivity contains a MapView that contains the FeatureLayer. Spinners are populated with values from two fields in the table. The values from the spinners are used to construct a where clause which is then used in the queryFeatures method call.

The results of the query are reported to the user in the query callback, and the features in the query result are used to select features in the FeatureLayer in the MapView.

Sample Code

/* Copyright 2014 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.arcgis.android.samples.featureservicetablequery;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

import com.esri.android.map.FeatureLayer;
import com.esri.android.map.MapView;
import com.esri.arcgis.android.samples.fstquery.R;
import com.esri.core.geodatabase.GeodatabaseFeatureServiceTable;
import com.esri.core.geodatabase.GeodatabaseFeatureServiceTable.Status;
import com.esri.core.map.CallbackListener;
import com.esri.core.map.CodedValueDomain;
import com.esri.core.map.Feature;
import com.esri.core.map.FeatureResult;
import com.esri.core.map.Field;
import com.esri.core.tasks.query.QueryParameters;

public class FeatureServiceTableQueryActivity extends Activity {

  final String FEATURE_SERVICE_URL = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/FeatureServer";

  final String DAMAGE_FIELD_NAME = "typdamage";

  final String CAUSE_FIELD_NAME = "primcause";

  public FeatureLayer featureLayer;

  public GeodatabaseFeatureServiceTable featureServiceTable;

  MapView mMapView;

  Spinner mDamageSpinner;

  Spinner mCauseSpinner;

  ArrayAdapter<String> damageAdapter;

  ArrayAdapter<String> causeAdapter;

  /** Called when the activity is first created. */
  public void onCreate(Bundle savedInstanceState) {

    // Get references to the map in the layout.
    mMapView = (MapView) findViewById(R.id.map);

    // Create a GeodatabaseFeatureServiceTable from the URL of a feature service.
    featureServiceTable = new GeodatabaseFeatureServiceTable(FEATURE_SERVICE_URL, 0);

    // Initialize this GeodatabaseFeatureService to fill it with features from the service.
    featureServiceTable.initialize(new CallbackListener<GeodatabaseFeatureServiceTable.Status>() {

      public void onError(Throwable ex) {
        showToast("Error initializing FeatureServiceTable");

      public void onCallback(Status arg0) {

        // Create a FeatureLayer from the initialized GeodatabaseFeatureServiceTable.
        featureLayer = new FeatureLayer(featureServiceTable);

        // Emphasize the selected features by increasing selection halo size.

        // Add the feature layer to the map.

        // Set up spinners to contain values from the layer to query against.

        // Get the fields that will be used to query the layer.
        Field damageField = featureServiceTable.getField(DAMAGE_FIELD_NAME);
        Field causeField = featureServiceTable.getField(CAUSE_FIELD_NAME);

        // Retrieve the possible domain values for each field and add to the spinner data adapters.
        CodedValueDomain damageDomain = (CodedValueDomain) damageField.getDomain();
        CodedValueDomain causeDomain = (CodedValueDomain) causeField.getDomain();

        // On the main thread, connect up the spinners with the filled data adapters.
        runOnUiThread(new Runnable() {
          public void run() {

  public void onClick_okButton(View v) {
    // Build and execute the query.

    // First, check layer exists, and clear any previous selection from the layer.
    if (featureLayer == null) {
      showToast("Feature layer is not set.");

    // Build query predicates to construct a query where clause from selected values.
    String damageType = String.valueOf(mDamageSpinner.getSelectedItem());
    String primCause = String.valueOf(mCauseSpinner.getSelectedItem());
    String whereClause = "typdamage LIKE '" + damageType + "' AND primcause LIKE '" + primCause + "'";

    // Create query parameters, based on the constructed where clause.
    QueryParameters queryParams = new QueryParameters();

    // Execute the query and create a callback for dealing with the results of the query.
    featureServiceTable.queryFeatures(queryParams, new CallbackListener<FeatureResult>() {

      public void onError(Throwable ex) {
        // Highlight errors to the user.
        showToast("Error querying FeatureServiceTable");

      public void onCallback(FeatureResult objs) {

        // If there are no query results, inform user.
        if (objs.featureCount() < 1) {
          showToast("No results");

        // Report number of results to user.
        showToast("Found " + objs.featureCount() + " features.");

        // Iterate the results and select each feature.
        for (Object objFeature : objs) {
          Feature feature = (Feature) objFeature;

  public void setupQuerySpinners() {
    // Get the spinner controls from the layout.
    mDamageSpinner = (Spinner) findViewById(R.id.damageSpinner);
    mCauseSpinner = (Spinner) findViewById(R.id.causeSpinner);

    // Set up array adapters to contain the values in the spinners.
    damageAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item);
    causeAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item);

  public void showToast(final String message) {
    // Show toast message on the main thread only; this function can be
    // called from query callbacks that run on background threads.
    runOnUiThread(new Runnable() {
      public void run() {
        Toast.makeText(FeatureServiceTableQueryActivity.this, message, Toast.LENGTH_SHORT).show();

  protected void onDestroy() {

  protected void onPause() {

  protected void onResume() {

Feedback on this topic?