fix(map): render cluster markers in-scope to kill ClusterRenderer FATAL#5723
Merged
Conversation
Revert the shipped Canvas-marker + ViewTree-owner band-aid series (#5702-#5719, back to before #5684), which had lost the marker info-window popups and tap interactions, then fix the actual crash at its source. Root cause: only Clustering(clusterItemContent=...) crashes. maps-compose's ComposeUiClusterRenderer builds a detached ComposeView carrying a fake lifecycle owner and no SavedStateRegistryOwner -- the top Crashlytics FATAL in Navigation 3 / popup hierarchies. MarkerComposable already bakes its icon via the safe in-scope rememberComposeBitmapDescriptor, and info windows render with the live marker compositionContext, so InlineMap / NodeTrack / Traceroute were never affected and are left unchanged. NodeClusterMarkers now bakes each chip in-scope via rememberComposeBitmapDescriptor and hands the finished bitmaps to a custom DefaultClusterRenderer (icons assigned on the cluster's background thread, read-only -- it never composes). Native info windows (title/snippet) + onClusterItemInfoWindowClick -> node details and the precision circles are all preserved. Re-pins play-services-maps to 20.0.0 and removes MarkerBitmapRenderer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes the top Crashlytics FATAL on the map (the maps-compose cluster renderer crash) without losing the marker info-window popups and tap interactions.
Two parts:
Reverts the shipped Canvas-marker + ViewTree-owner band-aid series (fix(map): replace MarkerComposable with Canvas-rendered bitmaps #5702–fix(map): revert app-side Maps SDK init to library-idiomatic, fix inline-map crash #5719, back to before fix: address top Crashlytics crashes and non-fatals for build 29320984 #5684). That series had eliminated the crash by hand-drawing markers on a
Canvas, but in doing so it dropped the native info-window popups and click interactions and never actually closed the cluster crash (it kept mutating intoViewTreeLifecycleOwner!/ViewTreeSavedStateRegistryOwner!variants). This restoresMapView,WaypointMarkers,InlineMapto their pre-fix: address top Crashlytics crashes and non-fatals for build 29320984 #5684 state, deletesMarkerBitmapRenderer.kt, and re-pinsplay-services-mapsto20.0.0.Fixes the actual crash at its source, in one file (
NodeClusterMarkers.kt).Why / root cause
Verified against the
maps-compose 8.3.0+android-maps-utils 4.1.1source:MarkerComposablealready bakes its icon via the in-scoperememberComposeBitmapDescriptor(parented to the live, attached host view that has validViewTreeLifecycleOwner/SavedStateRegistryOwner), and info windows render with the live markercompositionContext. SoInlineMap/NodeTrack/Traceroutewere never the crash and are left untouched.Clustering(clusterItemContent = …)crashes: itsComposeUiClusterRenderercomposes each item in a detachedComposeViewthat carries only a fake lifecycle owner and noSavedStateRegistryOwner. In the Navigation 3 / popup hierarchies that ComposeView can't resolve those owners → FATAL.How
NodeClusterMarkersnow bakes each chip in the maps compose scope withrememberComposeBitmapDescriptor(node) { PulsingNodeChip(...) }(the real Compose chip, not a Canvas reimplementation) and hands the finishedBitmapDescriptors to a small customDefaultClusterRenderer:onBeforeClusterItemRendered/onClusterItemUpdated, which run on the cluster's background thread but are read-only — they look up a pre-baked descriptor and never compose, so the crash class is removed (not raced).supersets title/snippet fromNodeClusterItem) along withonClusterItemInfoWindowClick → navigate to node detailsandonClusterClick.unclusteredItemsstate (the library'sclusterItemDecorationcan't fire for a non-internal renderer, sinceClusterRendererItemStateisinternal).Reviewer notes
NodeClusterMarkers.kt; the other map files are pure reverts to a known-good state.node, so a bitmap is only re-rendered when that node changes. Fine for typical meshes.PulsingNodeChip's pulse is a one-shot animation; clustering already rendered it as a static bitmap, so nothing visual is lost by baking it.Verification
./gradlew :androidApp:compileGoogleDebugKotlin✅./gradlew spotlessCheck detekt✅./gradlew :androidApp:assembleGoogleDebug✅🤖 Generated with Claude Code