Skip to content

Let ImageIcon and GroundImageState take an image URL - #23

Merged
wf9a5m75 merged 3 commits into
developfrom
feat/image-icon-url
Nov 6, 2026
Merged

wf9a5m75 merged 3 commits into
developfrom
feat/image-icon-url

Conversation

@wf9a5m75

@wf9a5m75 wf9a5m75 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

ImageIcon(imageUrl, …) and GroundImageState(bounds, imageUrl, …) load their image from a URL. Same design as js-sdk-core and ios-sdk-core.

Behaviour

  • New internal RemoteImageLoader (@InternalMapConductorApi): one fetch per URL on Dispatchers.IO with HttpURLConnection (redirects followed by hand, as in KMLLoader), plus file and data URLs. Up to 32 MB of decoded bitmaps. A failed URL stays failed, logged once. No new dependencies.
  • ImageIcon: a second constructor with the same parameters as the Drawable one, labels included, plus imageUrl. Transparent at its final size and anchor until the image arrives; labels still draw. hashCode() = URL + parameters + load state, so it changes exactly once. copy() keeps the URL.
  • MarkerState: a pending URL icon registers a one-shot callback; on arrival, if the marker still holds that icon, it calls notifyMutated(). MarkerState.icon stays a plain read. A separate @InternalMapConductorApi iconRevision (Compose state) goes up on arrival, for overlays that cache bitmaps in composition (MapTiler, Longdo).
  • GroundImageState: new constructor and settable imageUrl. A 1 px transparent placeholder until loaded, then image is swapped. Results for an older URL are dropped. Setting image directly clears imageUrl.

API

Additions only (apiCheck passes).

Verification (TB520FU)

  • RemoteImageDeviceTest 6/6; core unit tests 290 pass; ktlint passes.
  • URL icon on Google Maps and MapLibre; with a 10 s delayed URL, label only → icon on arrival on Google Maps, MapLibre, MapTiler and Longdo (MapTiler/Longdo need their companion PRs).
  • Tiled path: 24,526 post-office markers with a delayed URL icon, on Google Maps and MapLibre: base map only, then every icon.
  • URL ground image on MapLibre. Google Maps ground images are blank on develop even without this change (pre-existing, not addressed here).

Companion PRs: android-sdk-compose (GroundImage overload), android-for-maptiler, android-for-longdo.

ImageIcon(imageUrl = ...) and GroundImageState(bounds, imageUrl = ...) load
the image themselves, matching react-sdk's GroundImageState.imageUrl. Until it
arrives the icon is transparent at its final size and anchor (a label is still
drawn) and the ground image is a 1 px transparent placeholder; when it arrives
the markers and ground images using it are redrawn.

- RemoteImageLoader fetches each URL once (http, https, file, data), keeps up
  to 32 MB of decoded bitmaps, remembers a failure for 30 s and logs it once.
  No new dependencies: HttpURLConnection with redirects followed by hand, as in
  android-kml's KMLLoader.
- A URL icon's hash is the URL plus whether the image has arrived, so it
  changes exactly once. toBitmapIcon() and the tile parts stay synchronous;
  BitmapIconCache keeps the placeholder and the real bitmap apart.
- MarkerState hears when a pending URL icon arrives and reports a write, but
  only if it still carries that icon. Nothing else re-reads icons, so without
  this the placeholder would stay until some other field changed.
- GroundImageState.imageUrl swaps `image` to the loaded bitmap if the URL is
  still the same; setting `image` clears imageUrl. copy() keeps the URL.

Public API: additions only (the two constructors and imageUrl getters/setter).
…ival

- A URL that fails to load now stays failed until the process restarts, as in
  react-sdk and ios-sdk; the 30 s retry is gone.
- MarkerState.icon also reads a counter that goes up when its URL icon's image
  arrives. The icon is the same instance before and after, so a composition
  that reads marker.icon (MapTiler and Longdo draw markers as Compose
  overlays) had no reason to run again.
- api: the GroundImageState(imageUrl) constructors moved with the source; the
  surface is unchanged.
…icon

Reading MarkerState.icon also read a Compose counter, and that getter runs
144k times on tile worker threads and in the controllers. The counter is now
a separate MarkerState.iconRevision (@InternalMapConductorApi, in its own
file so the API record keeps MarkerState); only overlays that draw markers in
Compose read it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant