Feature layers, like all layers, are visual representations of data and are used on a map or scene. In the case of feature layers, the underlying data is held in a feature table or feature service.
Feature services are useful for sharing vector GIS data with clients so that individual features can be queried, displayed, and edited. There are various online and offline methods to load feature services.
How to use the sample
Tap the button on the bottom menu to add feature layers, from different sources, to the map. Pan and zoom the map to view the feature layers.
How it works
Set the basemap with a BasemapStyle.
Load a feature layer with a URL.
i. Create a ServiceFeatureTable from a URL.
ii. Create a FeatureLayer with the feature table.
Load a feature layer with a portal item.
i. Create a PortalItem with the portal and item ID.
ii. Create a FeatureLayer with the portal item and with or without the layer ID.
Load a feature layer with a geodatabase.
i. Instantiate and load a Geodatabase using the file name.
ii. Get the feature table from the geodatabase with the feature table's name.
iii. Create a FeatureLayer from the feature table.
Load a feature layer with a geopackage.
i. Instantiate and load a geopackage using its file name.
ii. Get the first GeoPackageFeatureTable from the GeoPackage.geoPackageFeatureTables array.
iii. Create a FeatureLayer from the feature table.
Load a feature layer with a shapefile.
i. Create a ShapefileFeatureTable using the shapefile path.
ii. Create a FeatureLayer from the feature table and load it.
Add the feature layer to the map's OperationalLayers.
The Scottish Wildlife Trust shapefile data is provided from Scottish Wildlife Trust under CC-BY licence. Data Copyright Scottish Wildlife Trust (2022).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/* Copyright 2022 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/package com.esri.arcgismaps.sample.addfeaturelayers
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.arcgismaps.data.GeoPackage
import com.arcgismaps.data.Geodatabase
import com.arcgismaps.data.ServiceFeatureTable
import com.arcgismaps.data.ShapefileFeatureTable
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
import com.arcgismaps.mapping.layers.FeatureLayer
import com.arcgismaps.portal.Portal
import com.arcgismaps.mapping.PortalItem
import com.esri.arcgismaps.sample.addfeaturelayers.databinding.ActivityMainBinding
import kotlinx.coroutines.launch
import java.io.File
classMainActivity : AppCompatActivity() {
// set up data binding for the activityprivateval activityMainBinding: ActivityMainBinding by lazy {
DataBindingUtil.setContentView(this, R.layout.activity_main)
}
privateval mapView by lazy {
activityMainBinding.mapView
}
privateval provisionPath: String by lazy {
getExternalFilesDir(null)?.path.toString() + File.separator + getString(R.string.app_name)
}
// enum to keep track of the selected source to display the feature layerenumclassFeatureLayerSource(val menuPosition: Int) {
SERVICE_FEATURE_TABLE(0),
PORTAL_ITEM(1),
GEODATABASE(2),
GEOPACKAGE(3),
SHAPEFILE(4)
}
// keeps track of the previously selected feature layer sourceprivatevar previousSource: FeatureLayerSource? = nulloverridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// authentication with an API key or named user is// required to access basemaps and other location services ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.API_KEY)
lifecycle.addObserver(mapView)
// set the map to be displayed in as the BasemapStyle topographic activityMainBinding.mapView.map = ArcGISMap(BasemapStyle.ArcGISTopographic)
setUpBottomUI()
}
/**
* Sets the map using the [layer] at the given [viewpoint]
*/privatefunsetFeatureLayer(layer: FeatureLayer, viewpoint: Viewpoint) {
activityMainBinding.mapView.apply {
// clears the existing layer on the map map?.operationalLayers?.clear()
// adds the new layer to the map map?.operationalLayers?.add(layer)
// updates the viewpoint to the given viewpoint setViewpoint(viewpoint)
}
}
/**
* Load a feature layer with a URL
*/privatefunloadFeatureServiceURL() {
// initialize the service feature table using a URLval serviceFeatureTable =
ServiceFeatureTable(resources.getString(R.string.sample_service_url))
// create a feature layer with the feature tableval featureLayer = FeatureLayer.createWithFeatureTable(serviceFeatureTable)
val viewpoint = Viewpoint(41.70, -88.20, 120000.0)
// set the feature layer on the map setFeatureLayer(featureLayer, viewpoint)
}
/**
* Load a feature layer with a portal item
*/privatesuspendfunloadPortalItem() {
// set the portalval portal = Portal("https://www.arcgis.com")
// create the portal item with the item ID for the Portland tree service dataval portalItem = PortalItem(portal, "1759fd3e8a324358a0c58d9a687a8578")
portalItem.load().onSuccess {
// create the feature layer with the itemval featureLayer = FeatureLayer.createWithItem(portalItem)
// set the viewpoint to Portland, Oregonval viewpoint = Viewpoint(45.5266, -122.6219, 2500.0)
// set the feature layer on the map setFeatureLayer(featureLayer, viewpoint)
}.onFailure {
showError("Error loading portal item: ${it.message}")
}
}
/**
* Load a feature layer with a local geodatabase file
*/privatesuspendfunloadGeodatabase() {
// locate the .geodatabase file in the deviceval geodatabaseFile = File(provisionPath, getString(R.string.geodatabase_la_trails))
// instantiate the geodatabase with the file pathval geodatabase = Geodatabase(geodatabaseFile.path)
// load the geodatabase geodatabase.load().onSuccess {
// get the feature table with the nameval geodatabaseFeatureTable =
geodatabase.getFeatureTable("Trailheads")
if (geodatabaseFeatureTable == null) {
showError("Feature table name not found in geodatabase")
return }
// create a feature layer with the feature tableval featureLayer = FeatureLayer.createWithFeatureTable(geodatabaseFeatureTable)
// set the viewpoint to Malibu, Californiaval viewpoint = Viewpoint(34.0772, -118.7989, 600000.0)
// set the feature layer on the map setFeatureLayer(featureLayer, viewpoint)
}.onFailure {
showError("Error loading geodatabase: ${it.message}")
}
}
/**
* Load a feature layer with a local geopackage file
*/privatesuspendfunloadGeopackage() {
// locate the .gpkg file in the deviceval geopackageFile = File(provisionPath, "/AuroraCO.gpkg")
// instantiate the geopackage with the file pathval geoPackage = GeoPackage(geopackageFile.path)
// load the geopackage geoPackage.load().onSuccess {
// get the first feature table in the geopackageval geoPackageFeatureTable = geoPackage.geoPackageFeatureTables.first()
// create a feature layer with the feature tableval featureLayer = FeatureLayer.createWithFeatureTable(geoPackageFeatureTable)
// set the viewpoint to Denver, COval viewpoint = Viewpoint(39.7294, -104.8319, 500000.0)
// set the feature layer on the map setFeatureLayer(featureLayer, viewpoint)
}.onFailure {
showError("Error loading geopackage: ${it.message}")
}
}
/**
* Load a feature layer with a local shapefile file
*/privatesuspendfunloadShapefile() {
// locate the shape file in deviceval file = File(
provisionPath,
"/ScottishWildlifeTrust_ReserveBoundaries_20201102.shp" )
// create a shapefile feature table from a named bundle resourceval shapeFileTable = ShapefileFeatureTable(file.path)
shapeFileTable.load().onSuccess {
// create a feature layer for the shapefile feature tableval featureLayer = FeatureLayer.createWithFeatureTable(shapeFileTable)
// set the viewpoint to Scotlandval viewpoint = Viewpoint(56.641344, -3.889066, 6000000.0)
// set the feature layer on the map setFeatureLayer(featureLayer, viewpoint)
}.onFailure {
showError("Error loading shapefile: ${it.message}")
}
}
privatefunshowError(message: String) {
Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT).show()
Log.e(localClassName, message)
}
/**
* Sets up the bottom UI selector to switch between
* different ways to load a feature layers
*/privatefunsetUpBottomUI() {
// create an adapter with the types of feature layer// sources to be displayed in menuval adapter = ArrayAdapter(
this,
android.R.layout.simple_list_item_1,
resources.getStringArray(R.array.feature_layer_sources)
)
activityMainBinding.bottomListItems.apply {
// populate the bottom list with the feature layer sources setAdapter(adapter)
// click listener when feature layer source is selected setOnItemClickListener { _, _, i, _ ->
// get the selected feature layer sourceval selectedSource = FeatureLayerSource.values().find { it.menuPosition == i }
// check if the same feature is selectedif (previousSource != null && (previousSource == selectedSource)) {
// same feature layer selected, returnreturn@setOnItemClickListener }
lifecycleScope.launch {
// set the feature layer source using the selected sourcewhen (selectedSource) {
FeatureLayerSource.SERVICE_FEATURE_TABLE -> loadFeatureServiceURL()
FeatureLayerSource.PORTAL_ITEM -> loadPortalItem()
FeatureLayerSource.GEODATABASE -> loadGeodatabase()
FeatureLayerSource.GEOPACKAGE -> loadGeopackage()
FeatureLayerSource.SHAPEFILE -> loadShapefile()
else -> {}
}
}
// update the previous feature layer source previousSource = selectedSource
}
}
}
}