Edit an ArcGISFeatureLayer

Using the ArcGIS Runtime SDK for Java, you can edit feature services using methods on the ArcGISFeatureLayer class. An ArcGISFeatureLayer can be created from an online feature service URL. At version 10.2.3 of the SDK, an alternative editing model for online and offline data was introduced. With this model, you create a FeatureTable from either a feature service (online) or a local geodatabase (offline) and you perform edits directly on the feature table. You display the feature table's data in a map using the FeatureLayer class. For more information on this editing model, see the topic Edit features. For an overview of your editing options, see the Editing topic. The remainder of this topic focuses on editing an ArcGISFeatureLayer.

Edit a feature service

Additions, deletions, and updates of features in feature services are performed on an ArcGISFeatureLayer via the applyEdits method:

public void applyEdits(Graphic[] adds,
                       Graphic[] deletes,
                       Graphic[] updates,
                       CallbackListener<FeatureEditResult[][]> callback)

For new features that are added, applyEdits will submit all the features back to the geodatabase behind the service. If successful, all of the new features will be updated with the ObjectID (OID) and graphic ID and will be added to the layer. The OID comes from the database, whereas the graphic ID is client-side only and can change from one session to the next. For updates and deletes, the graphic features will be adjusted in the displayed layer based on a successful response as long as your feature layer is in the dynamic display mode called "on demand", which is the default mode. The response is handled within a CallbackListener, as shown in the following code example which adds a single point feature to a layer:

// obtain the clicked point from a MouseEvent
Point mapPt = map.toMapPoint(mouseEvent.getX(), mouseEvent.getY());
// create a map of attributes (keys must match fields in the feature layer)
Map<String,Object> attributes = new HashMap<String,Object>();
attributes.put("Type", "Park");
attributes.put("Description", "Editing...");
// prepare the Graphic to add
Graphic g = new Graphic(mapPt, new SimpleMarkerSymbol(Color.RED, 10, Style.CIRCLE), attributes, 0);
// put Graphic in an array (applyEdits takes Graphic arrays as parameters)
Graphic[] adds = {g};

arcGISFeatureLayer.applyEdits(
  adds,
  new Graphic[]{}, // no graphics to update
  new Graphic[]{}, // no graphics to delete
  new CallbackListener<FeatureEditResult[][]>(){

    @Override
    public void onCallback(FeatureEditResult[][] result) {
      // do something with the feature edit result object
    }

    @Override
    public void onError(Throwable e) {
      // handle the error
    }								
  }
);

What happens in this case is as follows:

  1. A new Graphic instance is created with a Point geometry and a collection of attributes.
  2. The graphic is added to a Graphic array.
  3. The applyEdits method is called, passing in the graphics to add to the feature layer.
  4. An anonymous CallbackListener is defined, handling the successful callback or errors that result.

Whether you are adding, updating, or deleting features, the same method on ArcGISFeatureLayer is used. It's up to you to decide how often you want to call the applyEdits method to push your edits back to the geodatabase; you can do it for each edit, as above, or store Graphic objects as they're edited, then commit several edits at once.

Get the edit capabilities

A feature service can have restrictions on what editing operations can be performed, and on which users can perform each operation. Using the API, you can obtain the overall capabilities of the service via the ArcGISFeatureLayer created from the service as follows:

String capabilities = arcGISFeatureLayer.getCapabilities();

The returned string will include editing capabilities, for example, at 10.1 or later, the service will specify whether it allows users to create, update, and/or delete features. It's good practice to check the capabilities of a service before sending an editing request through to the server, as an incompatible request will be rejected by the server and may represent wasted effort. You can also check whether the service's capabilities includes the 'Editing' capability using a single method call which returns true or false:

boolean isEditable = arcGISFeatureLayer.isEditable();

Geometry updates

At ArcGIS for Server 10.1 or later, a feature service may prevent geometries from being updated. This property is exposed in the Java API for feature layers through the isAllowGeometryUpdates() method. If this method returns false, feature geometries cannot be updated. This means that in your Java application, when you call the applyEdits method as described previously, geometries will not be sent through to the service to be updated. When geometry updates are not allowed by the service, you can still create new geometries and features, and you can still edit other feature properties such as their editable attributes.

It's recommended that you check whether geometry updates are allowed in your workflow, and if not, notify the user. A simplified workflow is as follows:

if (arcGISFeatureLayer.isAllowGeometryUpdates()) {
 
  // update the geometry of the graphic whose unique id is 'id'
  arcGISFeatureLayer.updateGraphic(id, newGeometry);
 
  // update attributes if desired
  Graphic graphicToEdit = arcGISFeatureLayer.getGraphic(id); 
  Map<String, Object> attributes = graphicToEdit.getAttributes();
  attributes.put(FIELD_TO_EDIT, "the new value");
  arcGISFeatureLayer.updateGraphic(id, attributes);
 
  arcGISFeatureLayer.applyEdits(
    null, 
    null, 
    new Graphic[] {graphicToEdit}, 
    new CallbackListener<FeatureEditResult[][]>() {
      // etc.
  });
} else {
  // notify the user geometries will not get updated
  // send through updates to the attributes only
}

Set the geodatabase version

Feature layers are created based on some geodatabase holding feature data, accessed through a feature service. The geodatabase can be versioned. If it is, it's possible to specify what version to use for the feature layer, providing a view of the data corresponding to that version. The following code is an example of creating a feature layer from a versioned feature service and setting a specific geodatabase version:

ArcGISFeatureLayer arcGISFeatureLayer = new ArcGISFeatureLayer(VERSIONED_FEATURE_SERVICE_URL);
String gdbVersion = "SDE.myVersion";
arcGISFeatureLayer.setGdbVersion(gdbVersion);

Geodatabase versioning allows multiple users to edit the same data in an ArcSDE geodatabase without applying locks or duplicating data. For more information on geodatabase versioning, see the ArcGIS for Desktop help topic A quick tour of versioning. Note that file and personal geodatabases don't support versioning. Users always access an ArcSDE geodatabase through a version. When you connect to a multiuser geodatabase, you specify the version to which you will connect. If no version is specified, you connect to the default version.

In the Java API, you can specify the geodatabase version to use for a feature layer if the feature layer's data source is a versioned geodatabase as described previously. Methods on the ArcGISFeatureLayer class enable you to check whether the data in a feature layer you've created from a feature service is versioned, and if so, you can set the version to use for that feature layer. The version that you set will be used from that point on for operations such as viewing, editing, and querying features. You can set the geodatabase version for the feature layer before it's created, and you can also change it on the fly at any point after the layer has successfully initialized. If you try to set a version on a feature layer from an unversioned geodatabase, it will simply be ignored by the server and will not cause a failure in the feature layer.

The following code snippet shows how to create a feature layer from a versioned feature service, set a version, then print out the version once the layer has successfully initialized:

// create a versioned feature layer
final ArcGISFeatureLayer arcGISFeatureLayer = new ArcGISFeatureLayer(VERSIONED_FEATURE_LAYER_URL);
String gdbVersion = "SDE.myVersion";
arcGISFeatureLayer.setGdbVersion(gdbVersion);
 
arcGISFeatureLayer.addLayerInitializeCompleteListener(new LayerInitializeCompleteListener() {
  @Override
  public void layerInitializeComplete(LayerInitializeCompleteEvent e) {
    if (arcGISFeatureLayer.getStatus() == LayerStatus.INITIALIZED) {
      if (arcGISFeatureLayer.isDataVersioned()) {
        System.out.println("Current GDB version: " + arcGISFeatureLayer.getGdbVersion());
      } else {
        System.out.println("Data is not versioned.");
      }
    }
  }
});

Note:

Support for setting the geodatabase version was added to the REST API at the 10.1 release of ArcGIS for Server, so this operation is not supported for services prior to 10.1.