Performance considerations

There are several things you can do to improve the performance of your app, including designing better maps and scenes, using the appropriate rendering mode, and using graphics more efficiently.

Performance may be defined differently depending on the type of app you create. Mobile apps might require battery conservation, underpowered devices might require more efficient use of CPU and memory, apps with heavy analysis or geoprocessing may need to keep the UI thread responsive. To appropriately gauge performance for your app, you should test on devices that are representative of those on which your app will run, including the lower-end of the range.

Rendering mode

You can define a GraphicsRenderingMode for each GraphicsOverlay in your geoview and a FeatureRenderingMode for each FeatureLayer in the map. Setting the appropriate rendering mode for each layer and graphics overlay can help fine tune display performance for your app. The available rendering modes are described below.

  • Dynamic: Creates representations of the data on the device's graphics processing unit (GPU) and those representations essentially live on the GPU for the lifetime of the layer. A GPU based representation is created for every symbol (and geometry) and is drawn with every frame.

Rendering with the GPU is extremely fast and doesn't use much battery. Dynamic rendering mode is good for moving objects and for maintaining graphical fidelity during extent changes, since individual graphic changes can be efficiently applied directly to the GPU state. This provides a seamless look and feel when interacting with the display. The number of features or graphics has a direct impact on GPU resources and can therefore affect the responsiveness of user interaction. Ultimately, the number and complexity of objects that can be rendered in dynamic rendering mode is dependent on the power and memory of the GPU.

  • Static: Uses the device's central processing unit (CPU) to draw an image and then that image is pushed to the GPU to render. This is like creating a new picture every time the view needs to be redrawn (when the extent changes, for example). Optimizations in rendering prevent this from occurring with each view interaction, but may result in the map becoming blurry or blank before it eventually redraws.

Static mode only renders features and graphics when needed (for example, after an extent change) and offloads a significant portion of the graphical processing onto the CPU. As a result, less work is required by the GPU to draw, and the GPU can spend its resources on keeping the UI interactive. This mode is well-suited for stationary features or graphics, complex geometries, and very large numbers of features or graphics. The number of features and graphics has little impact on frame render time, meaning it scales well, and pushes a constant GPU payload. However, rendering updates is CPU and system memory intensive, which can have an impact on device battery life.

By default:

  • Graphics overlays render in dynamic rendering mode
  • Point feature layers render in dynamic rendering mode
  • Polyline and polygon feature layers render in static rendering mode

You can define LoadSettings to set the preferred rendering mode for feature layers of each geometry type in a map or scene.

As a general rule, it's typically better to use static rendering mode on complex geometries, such as polygon graphics with a large number of vertices.

Map and scene design

A map or scene is often the heart of your app, and there is a lot you can do to improve app performance without touching your code. The maps and scenes displayed by your apps should be designed for visual appeal and usability, as well as for performance.

Scale range

Features on the map should only be displayed at scales at which they are meaningful. This generally means not showing features at a small scale that can only be distinguished at a larger scale. For instance, displaying building footprints when the map is zoomed to the scale of a large city would likely draw what appears to be a single large polygon on the map. Setting a scale range for that layer would ensure that the buildings are only drawn when the user zooms the map to a scale at which individual features can be distinguished. Each layer in the map can have its own scale range defined to toggle layer display on and off as appropriate for the data.

You can define a visible scale range for layers using the ArcGIS Online map viewer, ArcGIS Pro, or programmatically by setting minimum and/or maximum scales for the Layer.

Designing a map with meaningful scale ranges for layers not only conserves drawing resources, it makes the information in the map more digestible for your user.

Layer order

Keeping layers with the same geometry type and rendering mode next to each other can improve performance by optimizing data transfer to the device's graphics processing unit (GPU). Layers in static rendering mode are rendered to an image on the central processing unit (CPU). Static rendering mode layers which are adjacent (in the stack) are combined and push the stack as a single set of textures to the GPU. In contrast, when static layers are not adjacent to one another (if interleaved with dynamic layers), multiple images are generated to preserve visibility ordering. In this case, multiple sets of textures must be pushed for each extent change, thereby negatively impacting performance.

Layer order does not affect layers in dynamic rendering mode, because all resources for the layers reside on the GPU, and the GPU can easily arrange these items when drawing.

Symbols

Some symbols perform better than others, especially when displaying a lot of features or graphics. In general, you should limit the use of composite symbols in favor of a DictionaryRenderer, limit the use of TextSymbol objects in favor of the labeling API (see the Add labels topic for details), and use a Renderer whenever possible to apply symbols to geoelements.

Additional tips for improving performance for graphics symbols are described in the graphics section below.

Spatial reference

When possible, you should use the same spatial reference for your map and all the layers and data it consumes. This also applies to large result sets returned from operations like geoprocessing, geocoding, or routing. Reprojecting data, as required, comes with a computational cost. Keeping your basemap and all operational layers in the same spatial reference can therefore greatly improve performance.

Graphics

Graphics are in-memory representations of geographic elements for display on a map view or scene view. They have a shape (point, line, or polygon geometry), a set of attributes, and a symbol. Graphics are created while the app is running and are not persisted between app sessions. For more information about graphics, see the Features and graphics topic.

There are several use cases for working with graphics. Some apps may only use a small number of graphics to show a few points of interest, text labels, and perhaps a user-defined sketch on the display. Others may have graphics-intensive workflows such as updating the symbols and locations for thousands of moving graphics in real time. For apps that only use a few graphics and that don't require frequent graphic updates, performance is unlikely to be affected by the things described in this section. For apps that rely on thousands of frequently updated graphics, however, significant performance improvements can be made by following some of the recommendations below.

Organize graphics

A graphics overlay can contain graphics of different geometry types and with different sets of attributes. For apps that only need to display a few graphics, maintaining all graphics in a single graphics overlay may provide an acceptable option. Graphics maintained this way typically have their own symbol to define their display: marker symbols for points, line symbols for polylines, and so on.

For apps that use a large number of graphics, there are performance benefits for organizing graphics according to their geometry type. As with the map layer order, keeping graphics overlays with the same geometry type and rendering mode next to each other can improve performance by optimizing data transfer to the GPU.

Organizing your graphics into the appropriate graphics overlays is a good first step to further improve performance by:

Use renderers

Graphics performance can be impacted not only by the number of graphics an app uses, but also by the number of symbols used to display them. An app with hundreds of graphics that each define their own symbol also uses hundreds of symbols. If designed correctly, a graphics overlay with thousands of graphics can be symbolized with just a handful of symbols.

Organizing graphics with the same geometry type into the same graphics overlay allows you to define graphic symbology by applying a renderer to the graphics overlay. A renderer uses one or several symbols, but those symbols are shared by all graphics in the graphics overlay, which can greatly reduce the number of symbols used in your app. If the graphics in your graphics overlay also have a consistent attribute schema, you can use those attributes to create a UniqueValueRenderer or ClassBreaksRenderer.

For more information about creating and applying a renderer, see Symbols, renderers, and styles.

Batch operations

Some graphics operations, such as adding graphics to a graphics overlay or adding attributes to a graphic, provide an option of working in batches rather than one object at a time. It's more efficient to pass a batch of objects into an object since it prevents events from being triggered for each individual addition, including drawing. Whenever you have code that works with individual graphics within a loop, you should explore alternatives that allow doing the same operations in a batch.

Adding graphics

GraphicsOverlay exposes a collection of graphics to which you can add and remove graphics. The graphics collection also provides the ability to add several objects by passing in a collection of things to add.

The commented code below shows adding graphics individually to a graphics overlay. The uncommented code adds the collection of graphics with a single method call.

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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    // Call the custom function that creates a list of Graphics.
    QList<Graphic*> graphics = createGraphics(identifyGraphicsOverlayResult);

    // This is not the best way to add a large list of graphics!
    // Loop through the list of graphics and add each one to the GraphicListModel.
    // for(Graphic* oneGraphic : graphics)
    // {
    //     GraphicListModel* graphicListModel = m_graphicsOverlay->graphics();
    //     graphicListModel->append(oneGraphic);
    // }

    // Better: simply add the entire list of graphics.
    GraphicListModel* graphicListModel = m_graphicsOverlay->graphics();
    graphicListModel->append(graphics);

Defining attributes

When constructing a Graphic, you have the option of passing in an object that defines a collection of attribute names and values. When creating a lot of graphics (that perhaps also have a lot of attributes), it's more efficient to use this constructor than adding attributes one at a time.

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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    // Option 1: This is not the best way to create a graphic with several attributes.
    // Create graphics from airport records in a custom table.
    for (Airport* airport : airportTable)
    {
        // Create a map point with Latitute and Longitude values from
        // the custom table using the WGS84 spatial reference.
        Point location(airport->longitude(), airport->latitude(), SpatialReference::wgs84());

        // Created a new graphic.
        Graphic* airportGraphic = new Graphic(location, this);

        // Add the attributes to the graphic.
        airportGraphic->attributes()->insertAttribute("ID", airport->id());
        airportGraphic->attributes()->insertAttribute("AirportType", airport->type());
        airportGraphic->attributes()->insertAttribute("Name", airport->name());
        airportGraphic->attributes()->insertAttribute("Keywords", airport->keywords());
        airportGraphic->attributes()->insertAttribute("Website", airport->website());
        airportGraphic->attributes()->insertAttribute("Phone", airport->phone());

        // Add the graphic to the list of graphics.
        graphics.append(airportGraphic);
    }

    // Option 2: This is a better way to create a graphic with several attributes (more performant).
    // Create graphics from airport records in a custom table.
    for (Airport* airport : airportTable)
    {
        // Create a map point with Latitute and Longitude values from the custom
        // table using the WGS84 spatial reference.
        Point location(airport->longitude(), airport->latitude(), SpatialReference::wgs84());

        // Add the attributes to a QVariantMap (with key/value pairs) of
        // attributes and pass it to the constructor.
        QVariantMap attributes;
        attributes.insert("ID", airport->id());
        attributes.insert("AirportType", airport->type());
        attributes.insert("Name", airport->name());
        attributes.insert("Keywords", airport->keywords());
        attributes.insert("Website", airport->website());
        attributes.insert("Phone", airport->phone());

        // Pass the location AND the attribute dictionary to the constructor.
        Graphic* airportGraphic = new Graphic(location, attributes, this);

        // Add the graphic to the list of graphics.
        graphics.append(airportGraphic);
    }

Reduce attributes

When working with a lot of graphics, it's best to keep them as lean as possible. You should only maintain attributes that are required for your app to: uniquely identify each graphic in the overlay, display a symbol for the graphic (with a unique value or class breaks renderer, for example), or to display information in a popup or label. If additional attribute information is needed to support functionality in your app, consider keeping that information in another data structure (such as a QHash) that uses the graphic's identifier as a unique key. If you created graphics by reading them from a data source, for example, you should be able to query the original data source using an ID that ties the graphic to a row in the table. This is similar to the technique described in this topic for maintaining a graphics lookup.

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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
        // You should only copy attributes that are directly required to draw and identify the graphics.
        attributes.insert("ID", airport->id()); // Needed to uniquely identify each graphic.
        attributes.insert("AirportType", airport->type()); // Needed by the unique value renderer.
        attributes.insert("Name", airport->name()); // Needed for labels.

        // These attributes can be read from the original source using the ID as a key.
        attributes.insert("Keywords", airport->keywords());
        attributes.insert("Website", airport->website());
        attributes.insert("Phone", airport->phone());

Maintain a graphics lookup

For an app that tracks objects in real time and updates their graphic representations on a map view or scene view, graphics updates need to be as fast and efficient as possible. Think of a vehicle control center that receives thousands of updates each second to update the location and status for a large fleet of vehicles, for example.

The first step when updating a graphic, of course, is to find the correct one to update. Your initial thought may be to store a unique ID as an attribute with each graphic and stream through all graphics in the overlay to find graphics by ID. This is a viable approach and would likely work well for apps that don't have too many graphics or that don't require updates too frequently.

A much faster approach, however, and one that works better for frequent graphic updates is to use a QHash (a collection of key-value pairs) to maintain a lookup of IDs and graphics. With this structure in place, updating graphics (perhaps by processing a stream of update messages) is simple. When an update comes in (a message is received, for example), a check is made against the lookup to see if a graphic already exists for the object (vehicle, for example). If it exists, the graphic update is made (its location and/or attribute values) and if it doesn't, a new graphic is created and added to both the graphics overlay and to the lookup.

For an example of this technique, see the blog article: Creating and updating 1000s of graphics in an ArcGIS Runtime app.

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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    // Create a point from the information in the update message.
    Point location(updateInfo->longitude(), updateInfo->latitude(), SpatialReference::wgs84());

    // See if the graphic is in the lookup dictionary/QMap.
    if (_graphicsLookup.contains(updateInfo->vehicleid()))
    {
        // Get the graphic from the lookup using the ID.
        Graphic* graphic = _graphicsLookup[updateInfo->vehicleid()];

        // Update location and status.
        graphic->setGeometry(location);
        graphic->attributes()->insertAttribute("Status", updateInfo->status());
    }
    else
    {
        // Create a new graphic using the location and status provided in the update message.
        QVariantMap attributes;
        attributes.insert("Status", updateInfo->status());
        Graphic* graphic = new Graphic(location, attributes, this);

        // Add the graphic to the overlay and to the lookup dictionary/QMap.
        _graphicsOverlay->graphics()->append(graphic);
        _graphicsLookup.insert(updateInfo->vehicleid(), graphic);
    }

Asynchronous programming

On mobile devices, where resources are limited and network speed is variable, it is advisable to not perform long running tasks on the main thread.

You should avoid running tasks on the main thread because your app may stop responding to user interaction and become unresponsive. A number of asynchronous methods are provided, which place work directly in the background, some methods are synchronous and you should always consider whether they could block the main thread. For example, finding the number of edits in a local geodatabase could block the main thread as the call is made to an external file and contains an unknown number of results. To ensure a good user experience and keep the solution scalable, you should avoid placing expensive tasks on the main thread.

See Threading basics in the Qt documentation for more information.

Network availability and speed

Mobile devices often use 3G or sometimes lower speed radio communication networks to obtain and transfer data. The speed of these networks vary but are much slower (in terms of data per second) than wired or wireless networks. Due to this network latency, even small requests can take time to return, which makes your application seem sluggish. Therefore, you need to carefully manage the total amount of data and the number of network requests submitted by your mobile application. As an example, it may be more efficient to send a single large request for data rather than multiple small requests. Changing the layer types, application functions, or the flow of your application can also affect network speed.

If your mobile application users are always in the range of a wireless network, your application can retrieve and submit larger amounts of data. However, even in this scenario, it's always good practice to remember the amount of data and number of requests your application uses, whatever the bandwidth.

By understanding the characteristics of the different types of map layers in the API, you can determine the best layers for your needs and ensure that your application performs for your users.

Some application users may only have intermittent network access, perhaps due to working in remote areas or scheduled daily access to a wireless network for synchronizing data. If this is the case, local storage usage is important. The application can be designed to connect to the server to retrieve data the user needs, then store this data on the local device. Applications need to be developed robustly with this in mind, because the network connection can be dropped anytime. Functions need to fail gracefully, and any long running application transactions may need to be rolled back.

More information

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