Select to view content in your preferred language

ANR when adding GraphicsOverlays with large graphic counts

142
0
Wednesday
CristhianSanchez
Occasional Contributor

Hello, our app loads user-submitted map features onto a map. Each feature has a geometry type (point, line, polygon) and a color. We group features into GraphicsOverlay objects by (type, color) pair — so a dataset with 3 geometry types × 5 colors produces at most 15 overlays, each containing N graphics. In production we see datasets with up to 15,000 total graphics spread across a small number of overlays (e.g. 2 overlays: 8,000 red points + 7,000 blue polygons).

We are seeing an ApplicationNotResponding error rooted in CoreVector.nativeAdd via pthread_mutex_lock:

at java.util.AbstractCollection.addAll
at com.arcgismaps.internal.collections.MutableListImpl.add
at com.arcgismaps.internal.jni.CoreVector.nativeAdd
at UnknownClass.RT_Vector_add
...
at UnknownClass.NonPI::MutexLockWithTimeout
at UnknownClass.__futex_wait_ex
at UnknownClass.syscall
 
This occurs most reliably on app resume after a long background period (60+ minutes) during which the SDK appears to have queued a large number of tile loads. When the app resumes, the rendering thread holds the native mutex during a tile burst, and our main thread blocks waiting to acquire it.
 
We came across the following post, which may be related to this issue: MapView is disposed way too long with a lot of Graphic in certain conditions 
 

What we do off the main thread

We build all GraphicsOverlay objects and populate overlay.graphics on a background IO dispatcher before touching mapView.graphicsOverlays:

// IO dispatcher
return withContext(Dispatchers.IO) {
    val overlay = GraphicsOverlay(renderingMode = GraphicsRenderingMode.Static)
    overlay.renderer = SimpleRenderer(symbol)
    overlay.labelDefinitions.add(labelDefinition)
    overlay.graphics.addAll(graphicsList)   // 8,000 graphics added here, off main
    overlay  // returned as a plain object, not yet registered
}

// Main dispatcher — MapView
withContext(Dispatchers.Main) {
    mapView.graphicsOverlays.add(overlay)   // registration: only this on main
}

 

Questions for the community:

1. Thread safety of graphicsOverlays.add()
Is it strictly required to call mapView.graphicsOverlays.add() on the main thread, or does the SDK provide any thread-safe API for registering overlays? GeoView extends FrameLayout, so we assume the Android single-threaded view rule applies — but we want to confirm.

2. Thread safety of overlay.graphics.addAll() before registration
We populate overlay.graphics on a background thread before calling graphicsOverlays.add(). Is this safe? Our assumption is that an unregistered overlay has no native render-thread involvement yet, so off-thread mutation is safe. Is this correct?

3. Recommended pattern for large graphic counts
Is there an recommended maximum number of graphics per overlay or per map view for GraphicsRenderingMode.Static before frame drops become significant? For 15,000 total graphics across 2 overlays on a modern high-end device, is per-overlay batching the right approach, or should we consider a different architecture (e.g. feature layers, clustering)?

4. Mutex contention on app resume
The ANR stack trace shows NonPI::MutexLockWithTimeout blocking on a futex. Is there a way to explicitly yield or pause the SDK's rendering pipeline during bulk overlay registration to avoid this contention on resume?

5. Alternative APIs for large static datasets
For a use case involving large numbers of static geometries — potentially 10,000+ features that do not change until the visible area is refreshed — is GraphicsOverlay the recommended API, or does the SDK provide alternative rendering approaches better suited to this scale? We are looking for guidance on what architecture would recommend when graphic counts grow beyond what GraphicsOverlay handles comfortably. 
 
Thanks in advance!
0 Replies