ArcGIS Runtime SDK for Android

Sync offline edits

Your users can edit offline and sync their edits to a feature service later when connectivity is restored. Syncing offline edits requires that a local a geodatabase is created from an existing sync-enabled feature service either from ArcGIS Online or ArcGIS Enterprise. A user can take a single sync-enabled feature service offline or a map containing one or more sync-enabled feature services offline.

If you take a single feature service offline and edit that single geodatabase, you can sync that local data with the feature service using the GeodatabaseSyncTask. Alternatively, if you take a whole map offline and create a geodatabase for each of the sync-enabled feature services in the map, you can sync all of the geodatabases in the map with one call using the OfflineMapSyncTask.

You should note that syncing can be performed, even if no edits have been made locally, to pull changes from the feature service into the local copy of the data.

Note:

A Basic license is required for editing.

Synchronize a single geodatabase

To synchronize edits made to a single geodatabase, do the following:

  1. Create a GeodatabaseSyncTask, passing in the URL of the feature service to be edited.
  2. Set up a callback to report on the progress while the synchronization happens by calling GeodatabaseSyncTask.addJobChangedListener().
  3. Set up a callback to report when the process finishes or fails by calling GeodatabaseSyncTask.addJobDoneListener().
  4. Set up the parameters for the synchronization task, using either the method on the sync task, or the SyncGeodatabaseParameters constructor.
  5. Call the syncGeodatabaseAsync method on GeodatabaseSyncTask to get a Job. Pass in the synchronization parameters, and the local geodatabase that contains the edits.
  6. Call start on the job to begin the sync operation.

private void createSyncParameters() {

  // Create SyncGeodatabaseParameters based on default parameters from the sync tasks
  final ListenableFuture<SyncGeodatabaseParameters> syncParamsFuture = geodatabaseSyncTask
      .createDefaultSyncGeodatabaseParametersAsync(geodatabase);
  syncParamsFuture.addDoneListener(new Runnable() {
    @Override
    public void run() {
      try
      {
        // Retrieve the SyncGeodatabaseParameters from the future
        syncParams = syncParamsFuture.get();

        // Continue on to sync the database using the parameters
        syncGeodatabase();
      } catch (InterruptedException | ExecutionException e) {
        dealWithException(e);
      }
    }
  });
}
private void syncGeodatabase() {

  // Start the sync operation on the geodatabase
  syncJob = geodatabaseSyncTask.syncGeodatabaseAsync(syncParams, geodatabase);

  // Add listener to check and report on the current sync status
  syncJob.addJobChangedListener(new Runnable() {
    @Override
    public void run() {

      // Deal with any errors found while syncing the geodatabase
      if (syncJob.getError() != null) {
        dealWithException(syncJob.getError());
      } else {
        // While job is in progress, review job messages or update progress in logs or user interface...
        updateUiWithJobProgress(syncJob);
      }
    }
  });

  // Add listener to deal with the completed job
  syncJob.addJobDoneListener(new Runnable() {
    @Override
    public void run() {
      // Check the job state is complete, deal with any errors
      if ((syncJob.getStatus() != Job.Status.SUCCEEDED) || (syncJob.getError() != null)) {
        dealWithException(syncJob.getError());
      } else {
        // Get the SyncLayerResults returned from the sync
        List<SyncLayerResult> syncResults = (List<SyncLayerResult>) syncJob.getResult();
        if (syncResults != null) {
          // Check sync results, for example update the UI to inform the user
          dealWithSyncResults(syncResults);
        }
      }
    }
  });

  // Start the Job to sync the geodatabase
  syncJob.start();
}
For example, once a local geodatabase has been edited by using FeatureTable.addFeatureAsync, edits can be synced back to the service by using these steps.

Note:
The sync operation overwrites previously synced edits to the same features on the service.

Internally, ArcGIS Runtime uses a geodatabase transaction to wrap the synchronization process. Since only one current transaction is permitted on a geodatabase, you will receive an error if you attempt to synchronize while another transaction is active (in an editing workflow, for example). Similarly, you may get an error if you try to start a transaction while synchronization is in progress. Errors that arise during a sync operation are returned in the callback when the job is done. For descriptions of errors that can arise when syncing offline edits, see Error handling with sync.

For services backed by non-versioned data, sync operations are performed per-layer, and are always bi-directional—that is, local edits are uploaded to the service, and then new edits are downloaded from the service. For services backed by versioned data, sync operations are per-geodatabase, and you can change the synchronization parameters to determine in which direction edits are synchronized—download only, upload only, or bi-directional. Use Geodatabase.getSyncModel() to find out if a geodatabase can be synchronized per-layer or per-geodatabase. Use SyncGeodatabaseParameters.setSyncDirection() to set the synchronization direction for a sync operation. When using bi-directional sync, note that the 'last in wins'—that is, uploaded edits will overwrite changes present on the server.

Synchronize a map

You can synchronize all the edits made to all the sync-enabled geodatabases in your map using the offline map sync task.

  • Create an OfflineMapSyncTask.
  • Add code to respond when the job is complete, by calling OfflineMapSyncTask.addJobDoneListener. Optionally, also call OfflineMapSyncTask.addJobStatusChanged in order to monitor a job's progress during it's execution.
  • Create an OfflineMapSyncParameters object with appropriate values.
  • Create an OfflineMapSyncJob by calling syncOfflineMap on the task, passing in the parameters object you defined.
  • Call OfflineMapSyncJob.start to start the sync job.
OfflineMapSyncTask offlineMapSyncTask = new OfflineMapSyncTask(map);

//create the offline map sync parameters
OfflineMapSyncParameters parameters = new OfflineMapSyncParameters();
parameters.setRollbackOnFailure(true);
parameters.setSyncDirection(SyncGeodatabaseParameters.SyncDirection.BIDIRECTIONAL);

//instantiate the sync job using the synchronization parameters
final OfflineMapSyncJob offlineMapSyncJob = offlineMapSyncTask.syncOfflineMap(parameters);

// Add listener to check and report on the current sync status
offlineMapSyncJob.addJobChangedListener(new Runnable() {
  @Override
  public void run() {

    // Deal with any errors found while syncing the map
    if (offlineMapSyncJob.getError() != null) {
      dealWithException(offlineMapSyncJob.getError());
    } else {
      // While job is in progress, review job messages or update progress in logs or user interface...
      updateUiWithJobProgress(offlineMapSyncJob);
    }
  }
});

// Add listener to deal with the completed job
offlineMapSyncJob.addJobDoneListener(new Runnable() {
  @Override
  public void run() {
    // Check the job state is complete, deal with any errors
    if ((offlineMapSyncJob.getStatus() != Job.Status.SUCCEEDED) || (offlineMapSyncJob.getError() != null)) {
      dealWithException(offlineMapSyncJob.getError());
    } else {
      // Get the OfflineMapSyncResult returned from the sync
      OfflineMapSyncResult result = offlineMapSyncJob.getResult();
      if (result != null) {
        // Check sync results, for example update the UI, deal with specific layer errors, etc
        dealWithSyncResults(result);
      }
    }
  }
});

//start the job
offlineMapSyncJob.start();

Register a geodatabase workflow

To work offline with a sync-enabled feature service, you need to download a geodatabase containing the features to your device. As mentioned in the Create an offline layer and Create an offline map topics, you can download a geodatabase to your device using any of these methods:

  • generateGeodatabaseAsync on GeodatabaseSyncTask
  • generateOfflineMap on OfflineMapTask
  • downloadPreplannedOfflineMap on OfflineMapTask
Each of these methods will automatically register the geodatabase with the feature service so that you can sync any changes with the feature service as described above.

If, however, you transfer that geodatabase file to another device, for example by side loading the file, the feature service will not be able to perform a sync with that geodatabase. If you wish to enable sync you must register the geodatabase with the feature service you used to generate the original geodatabase. To do this you must use the use registerSyncEnabledGeodatabaseAsync() method on GeodatabaseSyncTask to register each geodatabase copy (on each device). Registering in this way ensures each device receives the correct updates during sync operations.

Caution:

  • Registering a geodatabase with a feature service is not supported with a versioned feature service.
  • Once you call unregister on a geodatabase, you cannot re-register the same geodatabase.
  • If the original geodatabase is ever unregistered, no additional clients can use that copy to register.

For a list of benefits of this workflow, see create an offline layer.