Load FeatureTables and FeatureLayers from geodatabase

412
2
10-14-2022 03:27 AM
SimoneVitale
New Contributor

 

Hello,
I need to load some FeatureLayers and FeatureTables stored in a Geodatbase saved on the device, to my scene,
but when I try to add them to my scene I have an Exception that says "Object is already owned", but I have cleared
the collections before trying add and I don't understand why I have this error.
My code to load the data is:

                            try {
                                var geoDb = Geodatabase(fullPath)
                                geoDb.addDoneLoadingListener {
                                    try {
                                        if(geoDb.loadStatus == LoadStatus.LOADED){

                                            for(geoDbFeatureTable in geoDb.geodatabaseFeatureTables){
                                                val featureLayer = FeatureLayer(geoDbFeatureTable)
                                                //featureTables.add(geoDbFeature)
                                                //val featureLayer = FeatureLayer(geoDbFeature)
                                                featureTables.add(geoDbFeatureTable)

                                                try{
                                                    FeatureLayerUtils().setGraphicLayer(featureLayer, layer)
                                                    featureLayers.add(featureLayer)
                                                }
                                                catch (e: InterruptedException){
                                                    Log.e("LOGERROR", "Error identifying resuts: " + e.message)
                                                }
                                                catch (e : ExecutionException){
                                                    Log.e("LOGERROR", "Error identifying results: " + e.message)
                                                }
                                                // Aggiornamento del Bounding Box
                                                FeatureLayerUtils().updateBoundingBox(featureLayer, layer, arSceneView.originCamera.location)


                                                featureLayer.sceneProperties.altitudeOffset = layer.defaultObjectY.toDouble()
                                                featureLayer.sceneProperties.surfacePlacement = LayerSceneProperties.SurfacePlacement.RELATIVE
                                                featureLayer.isVisible = layer.visible
                                                featureLayersPair[layer] = featureLayer
                                                featureLayers.add(featureLayer)
                                                layerBoundingBoxPair[layer] = FeatureLayerUtils().createBoundingBox(arSceneView.originCamera.location, layer.maxDistanceFromOrigin.toDouble())
                                            }

                                            try {
                                                arSceneView.sceneView.scene.tables.clear()
                                                arSceneView.sceneView.scene.operationalLayers.clear()
                                                arSceneView.sceneView.scene.tables.addAll(featureTables)
                                                arSceneView.sceneView.scene.operationalLayers.addAll(featureLayers)
                                                viewModel.setTables(featureLayers)
                                                val tablesToFilter: Spinner = binding.assets.findViewById(R.id.tablesToFilter)
                                                tablesToFilter.adapter = AssetSpinnerAdapter(applicationContext, featureLayers)

                                                val featureLayer: FeatureLayer = featureLayers[0]
                                                viewModel.setTableFilters(FeatureLayerUtils().getFeatureLayerStringFields(featureLayer))
                                                val fieldFilters: Spinner = binding.assets.findViewById(R.id.fieldFilters)
                                                val editTextSearchAsset: EditText = binding.assets.findViewById(R.id.editTextSearchAsset)
                                                if (viewModel.uiState.value.tableFilters.isEmpty()) {
                                                    fieldFilters.visibility = View.GONE
                                                    editTextSearchAsset.visibility = View.GONE
                                                } else {
                                                    fieldFilters.adapter = AssetFilterSpinnerAdapter(applicationContext, viewModel.uiState.value.tableFilters)
                                                    fieldFilters.visibility = View.VISIBLE
                                                    editTextSearchAsset.visibility = View.VISIBLE
                                                }
                                            }
                                            catch (e : Exception){
                                                Log.d(TAG, "Error: " + e.message)
                                            }
                                        }
                                    }
                                    catch (e : Exception){
                                        Log.d(TAG, "Error")
                                    }
                                }
                                geoDb.loadAsync()
                            }
                            catch (e : Error){
                                Log.d(TAG, "Error")
                            }

Thanks yo all for the support! 

0 Kudos
2 Replies
Nicholas-Furness
Esri Regular Contributor

For performance reasons, where objects have a strong dependent relationship (e.g. a FeatureLayer is dependent on (or "owns") a FeatureTable), that is limited to a single "owner" at a time.

It looks like you do not need this line:

 

arSceneView.sceneView.scene.tables.addAll(featureTables)

 

You are taking the feature tables that you have already created feature layers for (i.e. each FeatureTable is already "owned" by a FeatureLayer) and trying to add them to the Scene's tables collection. This will try to set the Scene as the table's owner, but the layer is already the owner.

The scene's tables property is for standalone tables that are not used by a layer (perhaps they're related to features and/or don't have geometry).

0 Kudos
simone-vitale-overit
New Contributor II

Hi Nicholas,

thank you!

I have made some changes in the loading method and now I have this:

var geoDb = Geodatabase(fullPath)
geoDb.addDoneLoadingListener {
    try {
        if(geoDb.loadStatus == LoadStatus.LOADED){
            val fLayers = geoDb.geodatabaseFeatureTables.map { featureTable -> FeatureLayer(featureTable) }
            arSceneView.sceneView.scene.operationalLayers.addAll(fLayers)
        }
    }
    catch (e : Exception){
        Log.d(TAG, "Error")
    }
}
geoDb.loadAsync()

but on the map I don't see anything.

The geodatabase is generated from a FeatureService that show some polygon on the map and if I load from remote I see al polygons, but loading from GeoDatabase not show anything.

To generate my Geodatabase from the remote service I use this code:

val generateGeoBdJob = geoDbSyncTask.generateGeodatabase(generatedParams, geoDBPath)
generateGeoBdJob.addStatusChangedListener{
    if(generateGeoBdJob.status == Job.Status.SUCCEEDED)
    {
        Log.d(TAG, "Local Data successfully created for $serviceName on internal storage")
        //response.add("Local Data successfully created for $serviceName on internal storage")
        val result =  generateGeoBdJob.result
        if(result != null)
        {
            val geoDBPath = result.path
            Log.d("TAG", "Current path of Geo Database: $geoDBPath")
            // TODO: Show a message to the user
        }
    }
    else if(generateGeoBdJob.status == Job.Status.FAILED)
    {
        val message : String = "Local Data for $serviceName not created."
        Log.d(TAG, message)
    }

    // Remove this job from list
    geoDbJobList.remove(generateGeoBdJob)
    // Check if this job is the last in the list and hide the loader
    if(geoDbJobList.isEmpty())
    {
        stopLoading()
    }

}
generateGeoBdJob.start()
 Do you see anything wrong in the generation of the GeoDB?
 
 
Thank you for your support.
0 Kudos