Skip To Content

Sync offline edits

In this topic

Your users can edit offline in a services pattern and later sync their edits back to a feature service when connected. Syncing offline edits requires that you've created a geodatabase using a sync-enabled feature service from ArcGIS for Server, ArcGIS Online, or Portal for ArcGIS, as described in Create an offline map. After users have made edits and are ready to sync their local copy of the data with the service, use GeodatabaseSyncTask to sync with the feature service. 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.

To synchronize edits, do the following:

  • Set up and connect to a slot to report on the progress while the synchronization happens.
  • Create or obtain sync parameters for the synchronization task.
  • Create a GeodatabaseSyncTask instance.
  • Call the syncGeodatabase method on the GeodatabaseSyncTask.
Note:
In a sync operation, edits most recently synced to the service will overwrite previously synced edits, regardless of time of edits.

For descriptions of errors that can arise when syncing offline edits, see Error handling with sync.

Register a geodatabase in a pre-planned workflow

In a services pattern workflow known as a pre-planned workflow, you generate the geodatabase once and load copies of it onto each user's device. If you've generated the geodatabase on the user's device with GeodatabaseSyncTask, you don't need to register a geodatabase.

In the pre-planned workflow, you use the registerGeodatabase() method to register each geodatabase copy (on each device) with the feature service you used to generate the original geodatabase. Registering in this way ensures each device receives the correct updates during sync operations.

Caution:

  • 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 Register a geodatabase in a pre-planned workflow in "Create an offline map."

Code sample

The following sample shows how to sync your offline edits back to a feature service.

// In the header, declare m_geodatabaseSyncTask as a member variable
 EsriRuntimeQt::GeodatabaseSyncTask* m_geodatabaseSyncTask;

 // Construct the GeodatabaseSyncTask
 m_geodatabaseSyncTask = new EsriRuntimeQt::GeodatabaseSyncTask(this);

 // Connect the GeodatabaseSyncTask's signals to slots
 connect(m_geodatabaseSyncTask, SIGNAL(geodatabaseStatus(const EsriRuntimeQt::GeodatabaseStatusInfo&)), this, SLOT(onGeodatabaseStatus(const EsriRuntimeQt::GeodatabaseStatusInfo&)));
 connect(m_geodatabaseSyncTask, SIGNAL(geodatabaseError(const EsriRuntimeQt::ServiceError&,QString)), this, SLOT(onGeodatabaseError(EsriRuntimeQt::ServiceError,QString)));
 connect(m_geodatabaseSyncTask, SIGNAL(syncGeodatabaseComplete(EsriRuntimeQt::GeodatabaseFeatureTableEditErrors*)), this, SLOT(onGeodatabaseSyncComplete(EsriRuntimeQt::GeodatabaseFeatureTableEditErrors*)));
    
 // Setup the sync parameters
 EsriRuntimeQt::SyncGeodatabaseParameters params(m_geodatabase->syncGeodatabaseParameters());  
 params.setSyncDirection(EsriRuntimeQt::SyncDirection::Bidirectional);
    
 // Call the sync operation
 m_geodatabaseSyncTask->syncGeodatabase(params, m_geodatabase);
 // . . .
    
 // Slot called when sync completes
 void local_geodatabase_editing_sample::onGeodatabaseSyncComplete(EsriRuntimeQt::GeodatabaseFeatureTableEditErrors* errors)
 {
   updateProgressBarUI(QString(), false);
   // requery feature service layer so it refreshes the UI.
   m_featureServiceLayer.requery();
 }

 // Slot called when sync/generate geodatabase is in progress and emits status signals
 void local_geodatabase_editing_sample::onGeodatabaseStatus(const EsriRuntimeQt::GeodatabaseStatusInfo& status)
 {
   // show job status
   QString statusString;

   if (m_cancelJob && status.status() != EsriRuntimeQt::GeodatabaseStatus::Cancelled)
   {
      if (status.status() == EsriRuntimeQt::GeodatabaseStatus::Pending ||
          status.status() == EsriRuntimeQt::GeodatabaseStatus::InProgress)
      {
        statusString = QString("Cancelling job: ") + status.jobId();
        m_geodatabaseSyncTask->cancelJob(status);
      }
      m_cancelJob = false;
   }
   else if (status.status() == EsriRuntimeQt::GeodatabaseStatus::Cancelled)
   {
     updateProgressBarUI(QString(), false);
     m_cancelJob = false;

     updateUI();
     return;
   }

   else if (status.status() == EsriRuntimeQt::GeodatabaseStatus::UploadingDelta)
   {
     statusString = QString(status.deltaUploadProgress()/1000 + "of" + status.deltaSize()/1000 + "KBs"));
   }

   else if (m_isGenerateGDB)
   {
     if (status.status() == EsriRuntimeQt::GeodatabaseStatus::Completed)
     {
       statusString = "Generate geodatabase complete. Downloading...";
     }
     else
     {
       // Generate geodatabase job accepted, poll status
       statusString = QString("Generate geodatabase status: ") +
            status.statusToString(status.status()) +
            QString("...");
     }
   }
   else if (m_isSync)
   {
     statusString = QString("Sync Geodatabase status: ") +
            status.statusToString(status.status()) +
            QString("...");
   }
   updateProgressBarUI(statusString, true);
 }

Related topics