ArcGIS Runtime APIs are built to be fast, but there are still ways you can improve performance. Performance can be improved through design decisions, by selecting the right hardware, and by choices you make within your application development environment.
To get the most performance from your app, consider these design decisions when working with feature layers and graphic overlays:
- Number of features, graphics and layers
- Layer ordering
- Geometry symbolization in each layer
- Rendering modes
- Texture compression
- Scale range
- Spatial reference
Your app's performance is affected by the number of features, graphics, and layers that can be rendered quickly in a map or scene. The major factors to consider are:
- The complexity of features or graphics
- The specifications of the target device
- Rendering mode (dynamic or static)
- The end-user experience
Typically, maps, and scenes will have in the order of 10s of layers.
Layers are arranged bottom to top in the map or scene:
- At the bottom is the basemap
- Next are the operational layers
- And on top are any graphics overlays
Within the operational layers grouping and graphics overlays grouping, keeping layers with the same type and rendering mode next to each other, in the layer stack, can improve performance by optimizing data transfer to the GPU.
Layers in static rendering mode are rendered to an image on the CPU. The Runtime will combine static rendering mode layers which are adjacent (in the layer stack) and push the stack as a single set of textures to the GPU. In contrast, when static layers are not adjacent to one another (in the layer stack), if interleaved with dynamic layers, the Runtime must generate multiple images 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.
While feature layers are limited to a single geometry type, graphics overlays can have any number of geometry types. If you are rendering many thousands of mixed geometry types (points, lines and polygons) in the same graphics overlay, you may get improved application performance by separating the graphics into graphic overlays which contain one geometry type.
Similarly, because the Runtime will try to reuse duplicate symbols, you should limit the number of different types of symbols for features or graphics within a single layer. Performance gains will be particularly noticeable in layers which contain large numbers of features or graphics.
For larger numbers of features or graphics, you should always use a renderer, which guarantees the reuse of symbol instances.
You can assign both symbols and renderers to feature layers and graphics overlays. You can still assign unique symbols to each graphic (in which case the symbol takes precedence) without a notable drop in performance, if the layers contain only a small number of features or graphics. The Runtime will reuse duplicate symbols where it can, but there is an overhead cost in this calculation.
You can also add features or graphics more efficiently using a renderer.
You can render both feature layers and graphics overlays in either dynamic or static rendering mode. 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
Should you choose to set the rendering mode yourself, keep the following considerations in mind:
- Dynamic rendering mode: In this mode, features and graphics are stored on the GPU. As a result, 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 gives the map or scene a seamless look and feel when interacting with it. The number of features and graphics has a direct impact on GPU resources, so large numbers of features or graphics can affect the responsiveness of maps or scenes to user interaction. Ultimately, the number and complexity of features and graphics that can be rendered in dynamic rendering mode is dependent on the power and memory of the GPU.
- Static rendering mode: This mode 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 the graphics, and the GPU can spend its resources on keeping the UI interactive. Use this mode for stationary 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.
Should you choose to specify the rendering mode, the rendering mode should be set before adding the feature layer or graphics overlay to a map or scene. This is because changing the rendering mode of a layer, after its been added to the a map or scene, forces a complete redraw of the map or scene.
For graphics overlays, setting the rendering mode is as simple as choosing the rendering mode at object instantiation. For feature layers, the rendering mode can be set either on the feature layer itself or on the map or scene's load settings, using the preferred feature rendering mode. Once a feature layer or graphics overlay has been added to a map or scene, the rendering mode should not be switched unless absolutely necessary.
Whether in a feature layer or graphics overlay, it's typically better to use static rendering mode on complex geometries (for example, polygons with a large number of vertices).
Texture compression reduces the file size for image files used for texture. A typical compression technique and file format for textures is JPG, however for mobile platforms especially, use the ETC2 compression technique to improve download times, consume less memory, and improve overall performance.
All geographical data has a scale within which the data is both useful and accurate. Limiting the scale (called scale range) at which features or graphics are drawn can also improve performance. For example, you may want to set a scale range to a feature layer showing bus routes, which will be removed from the map or scene when your user zooms out to a country boundary level.
Setting a scale range:
- Makes the map or scene less cluttered and easier to use
- Conserves GPU (in dynamic rendering mode) and CPU (in static rendering mode) resources
Reprojecting has a computational cost. By choosing the spatial reference early in the design of your app and ensuring that all data and layers are stored in the same spatial reference as your basemap, you can substantially improve performance.
The hardware that you choose may mean that you have more than one application development environment choice. Each of these will provide you with different ways to improve performance.
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.
These long running tasks can cause unresponsiveness if run on a UI thread. The Android system guards against unresponsive apps by showing "Application Not Responding" or ANR dialogs, which should be avoided at all costs. The design of the ArcGIS Runtime SDK for Android has taken this into account and implements a number of asynchronous methods which put tasks on a background thread (noticeable as they commonly return a java Future and take a Callback as a parameter such as
Locator.find() ), but many methods provide only synchronous calls that you will need to handle yourself.
Hardware is designed with functionality and specific needs in mind. Be sure to understand the capabilities of your hardware before adding the complexities of an application environment and the ArcGIS Runtime to your requirements.
Mobile devices have less processor and memory resources compared to standard desktop machines. For this reason, applications need to be developed to run in an efficient manner.
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, such as intermittent 4G access due to working in remote areas or 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.
There are various debug tools provided by the Android software development kit (SDK) that can help analyze these issues in more detail. SDK tools exist for profiling memory, and viewing thread and network activity. For more information, see the Debugging section in the Android Developer Guide.