Editing attributes
There are several steps required to perform attribute editing of existing features. The logic and information can also easily be applied to editing attributes for new features. An attribute editing sample has been developed to help you understand how an attribute editing application might be written, and this is shipped with the ArcGIS API for Android SDK and is therefore available via the Eclipse plug-in.
What do I need to edit attributes?
In writing an application to edit a feature's attributes, you need to know some information about the feature layer being edited. This includes information on the available editable fields, the type of data that each field contains, and whether a field represents a subtype or domain and what the values are. The ArcGISFeatureLayer class provides all this for you and will ensure data integrity. Once you have gathered this information, you need to present it to the user so that they can make edits. When data has been added, you can send the edits to the server using the feature layer's applyEdits() method. More information on each of these steps can be found below.
Inspecting the layers fields
The layers field information is the key to editing attributes and is available from the feature layer getFields() method, which returns an array of field objects. A field object tells you whether the field is editable and what type the field is (so you know what data the user can enter). A few useful code examples to show you how to inspect the layer fields follow:
This code snippet determines editable fields that a user could add data to with a keyboard (strings, numbers, and dates) by eliminating all the other field types:
public boolean isFieldValidForEditing(Field field) {
int fieldType = field.getFieldType();
if (field.isEditable() && fieldType != Field.esriFieldTypeOID && fieldType != Field.esriFieldTypeGeometry
&& fieldType != Field.esriFieldTypeBlob && fieldType != Field.esriFieldTypeRaster
&& fieldType != Field.esriFieldTypeGUID && fieldType != Field.esriFieldTypeXML) {
return true;
} else {
return false;
}
}
The method below determines the type of a field between a text, date, number and decimal and would allow you to add logic to handle each field type:
public void determineFieldType(Field field) {
if (field.getFieldType()== Field.esriFieldTypeString) {
return FieldType.STRING;
} else if (field.getFieldType() == Field.esriFieldTypeSmallInteger
|| field.getFieldType() == Field.esriFieldTypeInteger) {
return FieldType.NUMBER;
} else if (field.getFieldType() == Field.esriFieldTypeSingle
|| field.getFieldType()== Field.esriFieldTypeDouble) {
return FieldType.DECIMAL;
} else if (field.getFieldType() == Field.esriFieldTypeDate) {
return FieldType.DATE;
}
return null;
}
Presenting editable fields to the user
Once you know what type of data can be edited, you can present it to the user in the most appropriate format. The ArcGIS API for Android includes various View elements for you to do this. The EditText object is probably the most used view element to allow user input and is very flexible. Its size and field length can be set, along with the type of data input, so that the appropriate soft keyboard is shown.
The following EditText Android layout xml below shows how to set up a field for entering decimal numbers only (see the android:inputType attribute):
<EditText
android:id="@+id/field_value_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="100dp"
android:maxWidth="150dp"
android:padding="10dp"
android:textSize="16sp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="150dp"
android:inputType="numberSigned|numberDecimal">
</EditText>
For domains and subtypes, the Spinner object can be used. This represents a drop-down list and can be populated using an adapter. See how the attribute editing sample uses this method to create a pop-up dialog box.
Ensuring data integrity
Before you commit the data, it is good practice to convert the data into the correct format, as often in the ArcGIS API for Android, values that users have entered (from an EditText or Spinner view) are returned as a string. The code snippet above for determining the field type can be used so that relevant parsing of string values into the required data type (integers, dates, doubles, and so on) can be performed.
Using FeatureLayer.applyEdits()
Editing the attributes of an existing feature is essentially a feature update (rather than an add or delete, which are the other editing operation types). To do this, you can use the ArcGISFeatureLayers.applyEdits() asynchronous method. Updated graphics are passed in as the third argument. The updated Graphic object does not have to include all attributes, and it is possible to only pass in those attributes that have changed. However, the ObjectID attribute must be passed in for the edit to succeed. The following method shows this:
/**
* Applies updates to a string field for a single feature.
*/
public void applyAttributeUpdates(String newAttributeValue, Field newAttributeField, String ObjectID, ArcGISFeatureLayer featureLayer, SimpleMarkerSymbol symbol) {
Map<String, Object> attr = new HashMap<String, Object>();
attr.put(newAttributeField.getName(), newAttributeValue);
attr.put(featureLayer.getObjectIdField(), ObjectID);
graphic = new Graphic(geometry, symbol, attr, null);
featureLayer.applyEdits(null, null, new Graphic[] { graphic },
new CallbackListener<FeatureEditResult[][]>() {
public void onError(Throwable error) {
// TODO implement error code
}
public void onCallback(FeatureEditResult[][] editResult) {
// Check the response for success or failure
if (editResult[2] != null && editResult[2][0] != null && editResult[2][0].isSuccess()) {
// TODO implement success logic
}
}
});
}
A new CallbackListener needs to be created to handle the asynchronous response from the applyEdits() method. The onCallback() method receives a FeatureEditResult[ ][ ] multidimensional array object. This result object contains FeatureEditResult objects for every addition, deletion, and update. In the code above, editResult[0] would provide addition results; editResult[1], deletion results; and editResult[2], update results. A FeatureEditResult is returned for every feature edit. The case above only expects one result, which would be referenced by the following: editResult[2][0].
The onCallback() method is called even if there is an error with the edits, so you need to add some code like the above to check for success or failure. The onError() method will also fire after this method if there has been an error.