Create mobile geodatabase

View on GitHub

Create and share a mobile geodatabase.

Image of create mobile geodatabase

Use case

A mobile geodatabase is a collection of various types of GIS datasets contained in a single file (.geodatabase) on disk that can store, query, and manage spatial and nonspatial data. Mobile geodatabases are stored in a SQLite database and can contain up to 2 TB of portable data. Users can create, edit and share mobile geodatabases across ArcGIS Pro, ArcGIS Maps SDK applications, or any SQL software. These mobile geodatabases support both viewing and editing and enable new offline editing workflows that don’t require a feature service.

For example, a user would like to track the location of their device at various intervals to generate a heat map of the most visited locations. The user can add each location as a feature to a table and generate a mobile geodatabase. The user can then instantly share the mobile geodatabase to ArcGIS Pro to generate a heat map using the recorded locations stored as a geodatabase feature table.

How to use the sample

Tap on the map to add a feature symbolizing the user's location. Tap "View table" to view the contents of the geodatabase feature table. Once you have added the location points to the map, Tap on "Share Mobile Geodatabase" to retrieve the .geodatabase file which can then be imported into ArcGIS Pro or opened in an ArcGIS Maps SDK application.

How it works

  1. Create the Geodatabase from the mobile geodatabase location on file.
  2. Create a new TableDescription and add the list of FieldDescriptions to the table description.
  3. Create a GeodatabaseFeatureTable in the geodatabase from the TableDescription using Geodatabase.createTable().
  4. Create a feature on the selected map point using GeodatabaseFeatureTable.createFeature(featureAttributes, mapPoint).
  5. Add the feature to the table using GeodatabaseFeatureTable.addFeature(feature).
  6. Each feature added to the GeodatabaseFeatureTable is committed to the mobile geodatabase file.
  7. Close the mobile geodatabase to safely share the ".geodatabase" file using Geodatabase.close().

Relevant API

  • ArcGISFeature
  • FeatureLayer
  • FeatureTable
  • FieldDescription
  • Geodatabase
  • GeodatabaseFeatureTable
  • TableDescription

Additional information

Learn more about mobile geodatabases and how to utilize them on the ArcGIS Pro documentation page. The following mobile geodatabase behaviors are supported in ArcGIS Maps SDK applications: annotation, attachments, attribute rules, contingent values, dimensions, domains, feature-linked annotation, subtypes, utility network and relationship classes.

Learn more about the types of fields supported with mobile geodatabases on the ArcGIS Pro documentation page.

Tags

arcgis pro, database, feature, feature table, geodatabase, mobile geodatabase, sqlite

Sample Code

create_mobile_geodatabase.dart
Use dark colors for code blocksCopy
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
//
// Copyright 2024 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
//
//   https://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.
//

import 'dart:io';

import 'package:arcgis_maps/arcgis_maps.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';

import '../../utils/sample_state_support.dart';

class CreateMobileGeodatabase extends StatefulWidget {
  const CreateMobileGeodatabase({super.key});

  @override
  State<CreateMobileGeodatabase> createState() =>
      _CreateMobileGeodatabaseState();
}

class _CreateMobileGeodatabaseState extends State<CreateMobileGeodatabase>
    with SampleStateSupport {
  // Create a controller for the map view.
  final _mapViewController = ArcGISMapView.createController();
  // Declare a map to be loaded later.
  late final ArcGISMap _map;
  // A flag for when the map view is ready and controls can be used.
  var _ready = false;
  // A mobile Geodatabase to be created and shared.
  Geodatabase? _geodatabase;
  // A feature table to store the location history.
  GeodatabaseFeatureTable? _featureTable;
  // A counter to keep track of the number of features added.
  var _featureCount = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        top: false,
        child: Stack(
          children: [
            Column(
              children: [
                Expanded(
                  child: Stack(
                    children: [
                      // Add a map view to the widget tree and set a controller.
                      ArcGISMapView(
                        controllerProvider: () => _mapViewController,
                        onMapViewReady: onMapViewReady,
                        onTap: _ready ? onTap : null,
                      ),
                    ],
                  ),
                ),
                // Display the number of features added and a button to view the table.
                Padding(
                  padding: const EdgeInsets.fromLTRB(
                    10,
                    0,
                    10,
                    0,
                  ),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        'Number of features added: $_featureCount',
                      ),
                      ElevatedButton(
                        onPressed: _featureCount > 0 ? _displayTable : null,
                        child: const Text(
                          'View table',
                        ),
                      ),
                    ],
                  ),
                ),
                // Display a button to create and share the mobile geodatabase.
                Padding(
                  padding: const EdgeInsets.fromLTRB(
                    0,
                    10,
                    0,
                    10,
                  ),
                  child: ElevatedButton.icon(
                    onPressed: _featureCount > 0 ? _shareGeodatabaseUri : null,
                    icon: const Icon(
                      Icons.share,
                    ),
                    label: const Text(
                      'Share Mobile Geodatabase',
                    ),
                  ),
                ),
              ],
            ),
            // Display a progress indicator and prevent interaction
            // until state is ready.
            Visibility(
              visible: !_ready,
              child: SizedBox.expand(
                child: Container(
                  color: Colors.white30,
                  child: const Center(
                    child: CircularProgressIndicator(),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _geodatabase?.close();
    _geodatabase = null;
    _featureTable = null;
    super.dispose();
  }

  // When the map view is ready, create a map and set the viewpoint.
  void onMapViewReady() async {
    _map = ArcGISMap.withBasemapStyle(BasemapStyle.arcGISTopographic);
    _mapViewController.arcGISMap = _map;
    _mapViewController.setViewpoint(
      Viewpoint.withLatLongScale(
        latitude: 41.5,
        longitude: -100.0,
        scale: 100000000.0,
      ),
    );
    // Create the mobile geodatabase with a feature table to track
    // location history.
    await _setupGeodatabase();

    setState(() => _ready = true);
  }

  // When the map is tapped, add a feature to the feature table.
  void onTap(Offset localPosition) {
    final mapPoint = _mapViewController.screenToLocation(
      screen: localPosition,
    );
    if (mapPoint != null) _addFeature(mapPoint);
  }

  // Create a mobile geodatabase and a feature table to store location history.
  Future<void> _setupGeodatabase() async {
    final directory = await getApplicationDocumentsDirectory();
    final geodatabaseFile = File(
      '${directory.path}${Platform.pathSeparator}localHistory.geodatabase',
    );
    if (geodatabaseFile.existsSync()) geodatabaseFile.deleteSync();

    try {
      _geodatabase = await Geodatabase.create(fileUri: geodatabaseFile.uri);
      await _createGeodatabaseFeatureTable();
    } catch (e) {
      _showDialog(
        'Error',
        e.toString(),
      );
    }
    return Future.value();
  }

  // Create a feature table to store location history.
  Future<void> _createGeodatabaseFeatureTable() async {
    // Create and define a table description for the feature table.
    final tableDescription = TableDescription(
      name: 'LocationHistory',
    )
      ..geometryType = GeometryType.point
      ..spatialReference = SpatialReference.wgs84
      ..hasAttachments = false
      ..hasM = false
      ..hasZ = false;

    tableDescription.fieldDescriptions.addAll(
      [
        FieldDescription(
          name: 'oid',
          fieldType: FieldType.oid,
        ),
        FieldDescription(
          name: 'collection_timestamp',
          fieldType: FieldType.date,
        ),
      ],
    );

    // Create the feature table and add the associated feature layer to the map.
    try {
      _featureTable = await _geodatabase!.createTable(tableDescription);
      _map.operationalLayers.clear();
      _map.operationalLayers.add(
        FeatureLayer.withFeatureTable(_featureTable as GeodatabaseFeatureTable),
      );
      setState(() => _featureCount = _featureTable!.numberOfFeatures);
    } catch (e) {
      _showDialog(
        'Error',
        e.toString(),
      );
    }
    return Future.value();
  }

  // Add a feature to the feature table.
  void _addFeature(ArcGISPoint point) async {
    if (_featureTable == null) {
      return;
    }

    final attributes = {
      'collection_timestamp': DateTime.now(),
    };
    final newFeature = _featureTable!.createFeature(
      attributes: attributes,
      geometry: point,
    );
    await _featureTable!.addFeature(newFeature);
    setState(() => _featureCount = _featureTable!.numberOfFeatures);
  }

  // Display the attribute table in a dialog.
  void _displayTable() async {
    final queryResult = await _featureTable?.queryFeatures(QueryParameters());

    final dataRows = <DataRow>[];
    for (final feature in queryResult!.features()) {
      dataRows.add(
        DataRow(
          cells: [
            DataCell(
              Text(
                feature.attributes['oid'].toString(),
              ),
            ),
            DataCell(
              Text(
                feature.attributes['collection_timestamp'].toString(),
              ),
            ),
          ],
        ),
      );
    }
    if (mounted) {
      showDialog(
        context: context,
        barrierColor: Colors.transparent,
        builder: (context) {
          return SimpleDialog(
            shape: const RoundedRectangleBorder(
              borderRadius: BorderRadius.zero,
            ),
            children: [
              Padding(
                padding: const EdgeInsets.fromLTRB(
                  15,
                  5,
                  15,
                  10,
                ),
                child: SingleChildScrollView(
                  scrollDirection: Axis.vertical,
                  child: DataTable(
                    border: TableBorder.all(),
                    columns: const [
                      DataColumn(
                        label: Text('OID'),
                      ),
                      DataColumn(
                        label: Text('Collection Timestamp'),
                      ),
                    ],
                    rows: dataRows,
                  ),
                ),
              ),
              const Padding(
                padding: EdgeInsets.fromLTRB(
                  15,
                  0,
                  15,
                  10,
                ),
                child: Text(
                  'Attribute table loaded from the mobile geodatabase '
                  'file. File can be loaded on ArcGIS Pro or ArcGIS Maps SDK.',
                  style: TextStyle(
                    fontSize: 12.0,
                  ),
                ),
              ),
            ],
          );
        },
      );
    }
  }

  // Call platform share sheet and share the mobile geodatabase file URI.
  void _shareGeodatabaseUri() async {
    _geodatabase?.close();

    // Open the platform share sheet and share the mobile geodatabase file URI.
    await Share.share(
      subject: 'Sharing the geodatabase',
      _geodatabase!.fileUri.path,
    );

    // Create a new mobile geodatabase and feature table to start again.
    _setupGeodatabase();
  }

  // Display a dialog with a title and message.
  void _showDialog(String title, String message) {
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text(title),
          content: Text(message),
        );
      },
    );
  }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.