Repository navigation
Conversation
Code Coverage
|
935a9f7 to
7311570
Compare
Coverage (unit tests)Compared against
Line and branch coverage from unit test reports. History is recorded on the |
| key: String? = null, | ||
| crossinline init: CameraPositionState.() -> Unit = {} | ||
| ): CameraPositionState = rememberSaveable(key = key, saver = CameraPositionState.Saver) { | ||
| ): CameraPositionState = rememberSaveable(saver = CameraPositionState.Saver) { |
There was a problem hiding this comment.
This is inside the @Deprecated overload, so after this change key stays in the public signature and does nothing. Callers still compile, but their saved-state key flips from their string to currentCompositeKeyHashCode. Three consequences, none of which the compiler surfaces:
- State persisted under the old custom key isn't found after upgrade, so the camera resets once.
- Anyone sharing one key across two call sites silently loses that sharing.
- Anyone using
keyto distinguish iterations of the same call site (loop, pager) now collides, since positional scoping yields the same hash per iteration. The correct migration is wrapping in thekey(...)composable, which nothing in our KDoc currently says.
I grepped every rememberSaveable call site in the repo: the non-deprecated path at line 54 is already keyless, and all three remaining keyed sites are inside @Deprecated declarations. So this change buys nothing on the supported surface, and only alters APIs already on their way out.
Suggestion: leave the body as it was and silence the warning instead, then delete the overload wholesale at the next major, where removing key is an honest feat!: with a migration note.
@Suppress("DEPRECATION")
@Composable
public inline fun rememberCameraPositionState(
key: String? = null,
crossinline init: CameraPositionState.() -> Unit = {}
): CameraPositionState = rememberSaveable(key = key, saver = CameraPositionState.Saver) {If you'd rather keep it as written, that's defensible given the function is already deprecated, but it needs a release-note line pointing loop and pager users at key(...).
| key: String? = null, | ||
| position: LatLng = LatLng(0.0, 0.0) | ||
| ): MarkerState = rememberSaveable(key = key, saver = MarkerState.Saver) { | ||
| ): MarkerState = rememberSaveable(saver = MarkerState.Saver) { |
There was a problem hiding this comment.
Same as CameraPositionState.kt:75: key survives in the signature as a no-op.
One extra wrinkle here. The deprecation message on line 193 only talks about rememberUpdatedMarkerState and never mentions key, so a caller passing key gets no hint at all that its meaning changed. If we keep this change rather than suppressing, the message needs a sentence about it.
| replaceWith = ReplaceWith( | ||
| expression = """ | ||
| val markerState = rememberSaveable(key = key, saver = MarkerState.Saver) { | ||
| val markerState = rememberSaveable(saver = MarkerState.Saver) { |
There was a problem hiding this comment.
Non-blocking, but while we're in here: this ReplaceWith can't actually be applied by the IDE. It's a multi-line statement (val markerState = ...) rather than an expression, and it carries no imports for rememberSaveable / Saver. It also contradicts the message right above it, which says to use rememberUpdatedMarkerState.
Either ReplaceWith("rememberUpdatedMarkerState(position)") or dropping replaceWith entirely would be more honest than what's there today.
| @@ -158,15 +158,15 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>( | |||
|
|
|||
| val keys = clusters.flatMap { it.computeViewKeys() } | |||
There was a problem hiding this comment.
This is where the "optimize loops" in the title could actually land.
keys is a List, so key !in keys on line 164 is a linear scan run once per entry in keysToViews, making onClustersChanged O(n*m) on every cluster change. computeViewKeys() already returns a Set, so:
| val keys = clusters.flatMap { it.computeViewKeys() } | |
| val keys = clusters.flatMapTo(mutableSetOf()) { it.computeViewKeys() } |
That makes both membership checks O(1) and dedupes safely (the for (key in keys) loop below adds into a map, so duplicates were never wanted). With a few hundred markers this is the difference that's actually measurable, unlike the forEach to for swaps.
| remove() | ||
| viewInfo.onRemove() | ||
| } | ||
| val iterator = keysToViews.iterator() |
There was a problem hiding this comment.
This hunk is a genuine improvement. The old with(keysToViews.iterator()) { forEach { ... remove() } } was fragile, relying on the interplay between Iterator.forEach and MutableIterator.remove. The explicit while (hasNext()) is clearer and obviously correct. 👍
I'd just reframe it in the PR description though: the forEach to for swaps elsewhere (lines 127 and 169) are readability only. Iterable.forEach and Map.forEach are inline, so the bytecode is effectively identical and there's no perf win to claim there.
| import androidx.compose.runtime.Immutable | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.Companion.fromInt | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.NO_MOVEMENT_YET | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.UNKNOWN |
There was a problem hiding this comment.
Anchoring here since the two removed lines only exist on the left side of the diff.
The removed fromInt and NO_MOVEMENT_YET imports aren't unused: both are referenced from the enum's KDoc just below, in "[NO_MOVEMENT_YET] is used as the initial state..." and "...an unsupported integer value is provided to [fromInt]". Compilation is fine either way, but could you check the Dokka output still resolves both links after this?
It's also inconsistent: this UNKNOWN import is kept, and it's equally KDoc-only. Its one code use, ?: return UNKNOWN inside the companion, resolves as an enum member without any import. So by the same criterion it would go too. I'd drop all three or keep all three.
… and optimize loops
3eabff1 to
a6c3d7c
Compare
| key: String? = null, | ||
| crossinline init: CameraPositionState.() -> Unit = {} | ||
| ): CameraPositionState = rememberSaveable(key = key, saver = CameraPositionState.Saver) { | ||
| ): CameraPositionState = rememberSaveable(saver = CameraPositionState.Saver) { |
There was a problem hiding this comment.
With this change key is still part of the public signature of rememberCameraPositionState, but it is silently ignored. Anyone passing it to keep separate saved states (e.g. several maps in a list) would get a different behaviour now. Should we deprecate the key parameter and mention in the KDoc that it has no effect, instead of dropping it silently? What do you think?
| key: String? = null, | ||
| position: LatLng = LatLng(0.0, 0.0) | ||
| ): MarkerState = rememberSaveable(key = key, saver = MarkerState.Saver) { | ||
| ): MarkerState = rememberSaveable(saver = MarkerState.Saver) { |
There was a problem hiding this comment.
Same here: key is now unused. Since rememberMarkerState is already deprecated this is less critical, but could we at least document that key is ignored?
| import androidx.compose.runtime.Immutable | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.Companion.fromInt | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.NO_MOVEMENT_YET | ||
| import com.google.maps.android.compose.CameraMoveStartedReason.UNKNOWN |
There was a problem hiding this comment.
Just to understand it: were the removed imports only there for the KDoc links to fromInt and NO_MOVEMENT_YET? If so we might lose those links in the generated docs, or do I miss anything?
# Conflicts: # maps-compose/src/main/java/com/google/maps/android/compose/CameraPositionState.kt # maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt
- Keep passing 'key' to rememberSaveable in the deprecated rememberCameraPositionState and rememberMarkerState overloads and suppress the deprecation instead, so callers relying on a custom key keep their saved state. The overloads can be removed at the next major. - Point the rememberMarkerState ReplaceWith at rememberUpdatedMarkerState, matching the deprecation message and making the IDE quick fix usable. - Collect cluster view keys into a Set so membership checks in onClustersChanged are O(1) instead of a linear scan per entry. - Restore the CameraMoveStartedReason imports used by KDoc links.
Coverage (instrumentation tests)
Files
|
Summary
Lint and cleanup pass on clustering and the deprecated
remember*overloads.Changes
onClustersChangednow collects the view keys into aSet, so thekey !in keyschecks are O(1) instead of a linear scan per entry (previously O(n*m) on every cluster change). The removal loop uses an explicitwhile (iterator.hasNext())instead offorEach+remove(). The otherforEachtoforswaps are readability only.rememberCameraPositionState(key, init)andrememberMarkerState(key, position): these keep passingkeytorememberSaveableand suppress the Compose deprecation instead of dropping it. Dropping it would have leftkeyas a silent no-op in the public signature and changed saved-state behavior for existing callers. Both overloads are already deprecated and can be removed at the next major.rememberMarkerStateReplaceWithnow points atrememberUpdatedMarkerState(position), matching the deprecation message. The previous multi-line statement could not be applied by the IDE.The
CameraMoveStartedReasonimport removal was reverted, since those imports back the KDoc links tofromIntandNO_MOVEMENT_YET.No public API or behavior changes.