Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Performance and profiling

This page is integration guidance: the practices that keep map rendering, routing, and navigation responsive, and the readbacks the SDK exposes so you can measure your own integration on your own hardware and scenes. The project publishes no benchmark numbers; any figure you quote should come from your own device and your own route mix.

Construct the SDK once

  • Build one MapSdk object and register your providers once at startup. Re-registration replaces every slot (including a cached tile slot), so an accidental double registration silently reopens the cache and resets its tuning: register, then tune with setRasterTileCacheTimeToLive.
  • Keep a single MapNavigationController around the lifetime of a trip screen; subscriptions are explicit and cheap, but re-subscribing listeners is wasted work on every frame.

Frame the camera with the contract’s helpers

  • Prefer the fit_bounds camera constructor for route previews and search-result framing. It computes a top-down, north-up camera that keeps the whole box visible inside the insets you give it, instead of a hand-tuned zoom level that breaks on another screen size.
  • Give it real insets. Route cards, attribution, and sheets are overlays your application owns; the insets tell the camera what the map may not hide. The insets-aware framing is what keeps the destination inside the visible region on every device.
  • Read the camera back with the attribute getters (center, zoomLevel, bearingDegrees, pitchDegrees) when you need to persist or compare a pose; the camera carries no setters, so a new pose is a new constructor call.

Let the render loop stay explicit

  • Frames are explicit by design: the platform view drives draw from its own cadence (a display link or choreographer callback). Do not add a second render loop; serialize draws and never call draw again while a previous call is still in flight — a draw in flight reports the next frame busy, and the cadence retries it.
  • Poll frameSettled in the render pump to skip draw when a re-draw would present the same pixels: true when the camera, overlay list, and location indicator are unchanged and no pending tile pixels remain. This keeps battery cost near zero on a static map.
  • Read TileFrameStatistics from every draw. The four readiness counts (present, fallback, deferred, unavailable) always add up to the requested count, so a persistent slice of deferred tells you your per-frame fetch budget is the limiter on your network, and a slice of unavailable points at provider refusals rather than slow ones.
  • Feed gesture deltas through the SDK’s camera seam (pan by pixels, focal-point zoom and rotation) instead of moving the viewport yourself; the SDK clamps zoom and pitch through the camera’s own ranges and holds the focal point exactly.

Size the tile cache deliberately

  • Register the tile cache with an absolute byte budget that fits your product (the reference application’s demo budget is 16 MiB for the whole recorded fixture set). The budget is a registration-time fact: retuning it means re-registering.
  • Set the tile time-to-live live through setRasterTileCacheTimeToLive. Imagery-provider terms put a ceiling on what the cache may retain; a request above the ceiling is accepted and the ceiling clamps what is stored. Read rasterTileCacheTerms to display the effective value, the ceiling, and the default in a settings or diagnostics screen.
  • Do not set a zero time-to-live; the call is refused because it would expire every entry on capture.

Keep the provider path under your quota

  • The provider implementation carries a shared token-bucket rate limiter and bounded idempotent retries. Treat RateLimitExhausted as “retry after the next refill”, not as an error to surface in the UI.
  • Cache-then-network is the default shape of every provider call, so repeated identical requests inside the time-to-live cost no quota. The tile category defaults to a 30-day time-to-live, the imagery terms ceiling.
  • Batch what the contracts batch: the distance matrix answers every origin-destination pair in one call; fetching matrix cells one by one multiplies your request count for the same data.

Use offline where it pays

  • The offline routing provider answers routes over a memory-mapped archive with A*; no network round trip. Compile an extract sized to the region your users drive in, not the planet: the compiler is deterministic and the archive is self-describing.
  • The routing decorator retries over the offline graph when the online provider fails, so a coverage-limited archive is a graceful degradation, not a failure mode. Its maneuver texts stay honest where the archive carries no street names.

Profile with the SDK’s own readbacks

  • Subscribe to diagnostics events at Info severity (or Debug for frame-path detail). Events stream fire-and-forget from bounded ring buffers, coordinates are scrubbed at the sink, and a slow listener can never slow the SDK.
  • Drain the backlog with the bounded flush readback from a non-frame context: the flush is synchronous and must stay out of the render path.
  • For provider failures, read latestProviderFailureDiagnostics after a suspicious session; the ring carries the contract, method, timestamp, and verbatim failure text for every failed foreign-callback provider call.
  • Measure on your target device and your real scenes. The SDK reports what it did (tile counts, frame statistics, cache terms); the timing numbers that matter are the ones your profiling run produces.