How to load FeatureLayer from offline geodatabase after generating it from feature service?

887
2
11-05-2016 10:37 PM
DotMatrix
New Contributor II

I took one of the Feature Editing samples, and changed it so it's purely offline because for my use the user will never be editing the server directly. In the morning they will generate a new geodatabase while connected to our internal wifi, then go into the field and make edits, and then sync edits back at the office while connected to our internal wifi.

The problem I'm having is that after the geodatabase is generated, the Feature Layer is not added to the map! If I close the app and reopen it, then the layer is visible, but the replica is no longer attached for syncing.

How can I get the Feature Layers to load AFTER the geodatabase is generated? Thanks

// Copyright 2015 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.
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import ArcGIS.Runtime 10.26
import ArcGIS.Extras 1.0
import QtPositioning 5.7
ApplicationWindow {
 id: appWindow
 width: 800
 height: 600
 title: "Tree Trimming"
property real scaleFactor: System.displayScaleFactor
 property int fontSize: 15 * scaleFactor
 property string featuresUrl: "my/feature/service"
 property string gdbPath: "~/ArcGIS/Runtime/Data/Test/offlineSample.geodatabase"
 property var selectedFeatureId: null
Envelope {
 id: initialExtent
 spatialReference: map.spatialReference
 xMin: -13821343.454522012
 yMin: 5631086.281941083
 xMax: -13732523.627654603
 yMax: 5754761.393706545
 }
Map {
 id: map
 anchors.fill: parent
 focus: true
 extent: initialExtent
ArcGISTiledMapServiceLayer {
 url: "http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer"
 }
FeatureLayer {
 id: offlineLayer
 featureTable: local
 selectionColor: "cyan"
function hitTestFeatures(x, y) {
 var tolerance = Qt.platform.os === "ios"
 || Qt.platform.os === "android" ? 4 : 1
 var featureIds = offlineLayer.findFeatures(
 x, y, tolerance * scaleFactor, 1)
 if (featureIds.length > 0) {
 selectedFeatureId = featureIds[0]
 selectFeature(selectedFeatureId)
 statusText.text = "Tap anywhere to move the feature"
 }
 }
 }
onMouseClicked: {
 if (offlineLayer.isFeatureSelected(selectedFeatureId)) {
 var featureToEdit = offlineLayer.featureTable.feature(
 selectedFeatureId)
 featureToEdit.geometry = mouse.mapPoint
 offlineLayer.featureTable.updateFeature(selectedFeatureId,
 featureToEdit)
 offlineLayer.unselectFeature(selectedFeatureId)
 selectedFeatureId = null
 syncButton.enabled = true
 statusText.text = "Tap on Sync to update the Feature Service with the edits"
 } else
 offlineLayer.hitTestFeatures(mouse.x, mouse.y)
 }
 }
GeodatabaseFeatureTable {
 id: local
 geodatabase: gdb.valid ? gdb : null
 featureServiceLayerId: 2
 }
ServiceInfoTask {
 id: serviceInfoTask
 url: featuresUrl
onFeatureServiceInfoStatusChanged: {
if (featureServiceInfoStatus === Enums.FeatureServiceInfoStatusCompleted) {
 //statusText.text = "Service info received. Tap on the Generate Geodatabase Button"
 statusText.text = gdb.valid
generateButton.enabled = true
 } else if (featureServiceInfoStatus === Enums.FeatureServiceInfoStatusErrored) {
 statusText.text = "Error:" + errorString
 generateButton.enabled = false
 cancelButton.text = "Start Over"
 }
 }
 }
SyncGeodatabaseParameters {
 id: syncGeodatabaseParameters
 syncDirection: Enums.SyncDirectionBidirectional
 }
Feature {
 id: featureToEdit
 }
Rectangle {
 anchors {
 fill: controlsColumn
 margins: -10 * scaleFactor
 }
 color: "lightgrey"
 radius: 5 * scaleFactor
 border.color: "black"
 opacity: 0.77
MouseArea {
 anchors.fill: parent
 onClicked: (mouse.accepted = true)
 }
 }
Column {
 id: controlsColumn
 anchors {
 left: parent.left
 top: parent.top
 margins: 20 * scaleFactor
 }
 spacing: 7
Button {
 id: generateButton
 text: "Generate Geodatabase"
 enabled: false
 style: ButtonStyle {
 label: Text {
 text: control.text
 color: control.enabled ? "black" : "grey"
 horizontalAlignment: Text.AlignHCenter
 }
 }
onClicked: {
 generateGeodatabaseParameters.initialize(
 serviceInfoTask.featureServiceInfo)
 generateGeodatabaseParameters.extent = map.extent
 generateGeodatabaseParameters.returnAttachments = false
 statusText.text = "Starting generate geodatabase task"
 geodatabaseSyncTask.generateGeodatabase(
 generateGeodatabaseParameters, gdbPath)
 }
 }
Button {
 id: syncButton
 text: "Sync"
 width: generateButton.width
 enabled: false
 style: generateButton.style
onClicked: {
 enabled = false
 geodatabaseSyncTask.syncGeodatabase(syncGeodatabaseParameters,
 gdb)
 statusText.text = "Starting sync task"
 }
 }
Button {
 id: cancelButton
 text: "Cancel"
 width: generateButton.width
 enabled: false
 style: generateButton.style
onClicked: {
 geodatabaseSyncTask.cancelJob(syncStatusInfo)
 enabled = false
 text = "Cancel"
 }
 }
 }
Geodatabase {
 id: gdb
 path: gdbPath
 }
GeodatabaseSyncStatusInfo {
 id: syncStatusInfo
 }
GeodatabaseSyncTask {
 id: geodatabaseSyncTask
 url: featuresUrl
onGenerateStatusChanged: {
 if (generateStatus === Enums.GenerateStatusCompleted) {
 statusText.text = geodatabasePath
 cancelButton.enabled = false
 generateButton.enabled = false
statusText.text = "Select a feature"
 } else if (generateStatus === GeodatabaseSyncTask.GenerateError) {
 statusText.text = "Error: " + generateGeodatabaseError.message
 + " Code= " + generateGeodatabaseError.code.toString(
 ) + " " + generateGeodatabaseError.details
 generateButton.enabled = false
 cancelButton.text = "Start Over"
 }
 }
onGeodatabaseSyncStatusInfoChanged: {
 if (geodatabaseSyncStatusInfo.status === Enums.GeodatabaseStatusUploadingDelta) {
 var deltaProgress = geodatabaseSyncStatusInfo.deltaUploadProgress / 1000
 var deltaSize = geodatabaseSyncStatusInfo.deltaSize / 1000
 statusText.text = geodatabaseSyncStatusInfo.statusString + " " + String(
 deltaProgress) + " of " + String(
 deltaSize) + " KBs..."
 } else
 statusText.text = geodatabaseSyncStatusInfo.statusString + "..."
 if (geodatabaseSyncStatusInfo.status !== GeodatabaseSyncStatusInfo.Cancelled)
 cancelButton.enabled = true
 syncStatusInfo.json = geodatabaseSyncStatusInfo.json
 }
onSyncStatusChanged: {
 if (syncStatus === Enums.SyncStatusCompleted) {
 cancelButton.enabled = false
 syncButton.enabled = false
 statusText.text = "Sync completed. You may continue editing the features."
 }
 if (syncStatus === Enums.SyncStatusErrored)
 statusText.text = "Error: " + syncGeodatabaseError.message
 + " Code= " + syncGeodatabaseError.code.toString(
 ) + " " + syncGeodatabaseError.details
 }
 }
GenerateGeodatabaseParameters {
 id: generateGeodatabaseParameters
 }
Rectangle {
 id: textStatusRectangle
 anchors {
 fill: statusText
 margins: -10 * scaleFactor
 }
 visible: statusText.text.length > 0
 color: "lightgrey"
 radius: 5
 border.color: "black"
 opacity: 0.77
 }
Text {
 id: statusText
 anchors {
 left: parent.left
 right: parent.right
 bottom: parent.bottom
 margins: 20 * scaleFactor
 }
 wrapMode: Text.WordWrap
 color: "black"
 }
Rectangle {
 anchors.fill: parent
 color: "transparent"
 border {
 width: 0.5 * scaleFactor
 color: "black"
 }
 }
Component.onCompleted: {
 statusText.text = "Getting service info"
 serviceInfoTask.fetchFeatureServiceInfo()
 }
}
0 Kudos
2 Replies
DotMatrix
New Contributor II

BUMP

0 Kudos
LucasDanzinger
Esri Frequent Contributor

The local geodatabase editing sample switches over to use the local geodatabase. It uses a ternary operator to determine if it is online or offline, and if offline, it uses the local geodatabase feature table. This all happens through property binding. If you want to be explicit in your code, you could instead dynamically create a new FeatureLayer when the generateStatusChanged signal emits, using syntax like this: 

var fl = ArcGISRuntime.createObject("FeatureLayer");
fl.featureTable = local;
0 Kudos