Commit 5a7dc34
[Android] Map: Stop reloading a pin's icon on every cluster pass (#37774)
Fixes #37773
### Description of Change
`ReclusterPins` re-runs `AddPins` on every zoom change, and
`AddPinAsync` reloaded `Pin.ImageSource` unconditionally each time — a
Glide fetch plus a decode and rescale for every un-clustered pin, on
every pass. The `MarkerOptions` it writes the icon to already outlive
the markers built from them, so the work was redundant as soon as the
source had not changed.
`MapPinHandler` now records which image source produced the icon
currently on its `MarkerOptions`, and `AddPinAsync` skips the load while
it still matches.
The key comes from `GetClusterIconCacheKey`, the helper the cluster icon
cache already uses, rather than a reference comparison. That matters
twice:
- it compares by **value**, so a new but equivalent `ImageSource`
instance is recognised instead of forcing a reload;
- it returns `null` for a source that opted out of caching — a
`UriImageSource` with `CachingEnabled` false, or a non-positive
`CacheValidity` — and those always reload rather than being frozen for
the handler's lifetime. The helper's own comment states that rule for
the cluster cache; this reuses it rather than restating it.
The record is invalidated by the `ImageSource` mapper, which is the one
hook that always runs when the icon on the `MarkerOptions` goes stale —
on every `SetVirtualView`, including a handler reconnected to a
different pin, and on every `ImageSource` change.
The source is captured before the await **and re-checked after it**
before the icon and the key are written: `UpdatePinImageSourceAsync`
guards its own write the same way, and without the symmetric guard the
two writers race and a marker can be published with the older icon while
the change notification that would correct it has already been consumed.
`UpdatePinImageSourceAsync` writes the icon to the `MarkerOptions` as
well as the live marker and updates the key, reaching the platform
element through the non-throwing accessor since it resumes after an
await.
A cleared `ImageSource` now takes the previous icon off the reused
`MarkerOptions` (`SetIcon(null)`, Android's "use the default marker")
rather than leaving the pin rendering an image its source no longer
names.
Skipping the load also removes the await before `Map.AddMarker` on the
common path, so an un-clustered pin with an unchanged icon is added
synchronously instead of disappearing until its image resolves.
### Note on ordering
Split out of #37769 so the bug fix and this caching behaviour stay
separately reviewable. It applies independently, but #37769 is the one
that fixes broken behaviour — merge that first.
### Verification
Physical device (Samsung SM-X230, Android 15), clustering gallery using
pins whose icon is a PNG written to `FileSystem.CacheDirectory`, handler
instrumented at each boundary. Three zoom-in/zoom-out cycles over 25
clustered custom pins, merged with #37769: **19 image loads for 86
markers** instead of one load per marker, every de-clustered pin keeping
its icon, no Glide asserts, no recycled-bitmap errors, no crashes.
Re-measured after adding the mapper-based invalidation, to confirm it
does not fire on the recluster path — `ReclusterPins` reuses the
existing handler with an unchanged `VirtualView`, so the mapper does not
re-run there.
### Issues Fixed
Fixes #37773
---------
Co-authored-by: Kévin Baumeyer <kbaumeyer@divalto.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent 5b04af5 commit 5a7dc34
4 files changed
Lines changed: 140 additions & 56 deletions
File tree
- src
- Controls/tests/Core.UnitTests
- Core/maps/src
- Handlers/Map
- Platform/iOS
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1442 | 1442 | | |
1443 | 1443 | | |
1444 | 1444 | | |
1445 | | - | |
| 1445 | + | |
1446 | 1446 | | |
1447 | 1447 | | |
1448 | 1448 | | |
1449 | 1449 | | |
1450 | | - | |
1451 | | - | |
| 1450 | + | |
| 1451 | + | |
1452 | 1452 | | |
1453 | 1453 | | |
1454 | 1454 | | |
1455 | 1455 | | |
1456 | 1456 | | |
1457 | 1457 | | |
1458 | 1458 | | |
1459 | | - | |
| 1459 | + | |
1460 | 1460 | | |
1461 | 1461 | | |
1462 | 1462 | | |
1463 | 1463 | | |
1464 | 1464 | | |
1465 | 1465 | | |
1466 | | - | |
1467 | | - | |
| 1466 | + | |
| 1467 | + | |
1468 | 1468 | | |
1469 | 1469 | | |
1470 | 1470 | | |
1471 | 1471 | | |
1472 | 1472 | | |
1473 | 1473 | | |
1474 | 1474 | | |
1475 | | - | |
| 1475 | + | |
1476 | 1476 | | |
1477 | 1477 | | |
1478 | 1478 | | |
| |||
1481 | 1481 | | |
1482 | 1482 | | |
1483 | 1483 | | |
1484 | | - | |
| 1484 | + | |
1485 | 1485 | | |
1486 | 1486 | | |
1487 | 1487 | | |
1488 | | - | |
| 1488 | + | |
1489 | 1489 | | |
1490 | 1490 | | |
1491 | 1491 | | |
1492 | | - | |
| 1492 | + | |
1493 | 1493 | | |
1494 | 1494 | | |
1495 | 1495 | | |
1496 | 1496 | | |
1497 | 1497 | | |
1498 | 1498 | | |
1499 | | - | |
| 1499 | + | |
1500 | 1500 | | |
1501 | 1501 | | |
1502 | 1502 | | |
| |||
1511 | 1511 | | |
1512 | 1512 | | |
1513 | 1513 | | |
1514 | | - | |
1515 | | - | |
| 1514 | + | |
| 1515 | + | |
1516 | 1516 | | |
1517 | 1517 | | |
1518 | 1518 | | |
1519 | 1519 | | |
1520 | 1520 | | |
1521 | 1521 | | |
1522 | 1522 | | |
1523 | | - | |
| 1523 | + | |
1524 | 1524 | | |
1525 | 1525 | | |
1526 | 1526 | | |
| |||
1535 | 1535 | | |
1536 | 1536 | | |
1537 | 1537 | | |
1538 | | - | |
1539 | | - | |
| 1538 | + | |
| 1539 | + | |
1540 | 1540 | | |
1541 | 1541 | | |
1542 | 1542 | | |
1543 | 1543 | | |
1544 | 1544 | | |
1545 | 1545 | | |
1546 | 1546 | | |
1547 | | - | |
| 1547 | + | |
1548 | 1548 | | |
1549 | 1549 | | |
1550 | 1550 | | |
1551 | | - | |
1552 | | - | |
| 1551 | + | |
| 1552 | + | |
1553 | 1553 | | |
1554 | 1554 | | |
1555 | 1555 | | |
1556 | | - | |
| 1556 | + | |
1557 | 1557 | | |
1558 | | - | |
| 1558 | + | |
1559 | 1559 | | |
1560 | 1560 | | |
1561 | 1561 | | |
| |||
1576 | 1576 | | |
1577 | 1577 | | |
1578 | 1578 | | |
1579 | | - | |
| 1579 | + | |
1580 | 1580 | | |
1581 | | - | |
| 1581 | + | |
1582 | 1582 | | |
1583 | 1583 | | |
1584 | 1584 | | |
| |||
1595 | 1595 | | |
1596 | 1596 | | |
1597 | 1597 | | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
| 1603 | + | |
| 1604 | + | |
| 1605 | + | |
| 1606 | + | |
| 1607 | + | |
| 1608 | + | |
| 1609 | + | |
| 1610 | + | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
1598 | 1644 | | |
1599 | 1645 | | |
1600 | 1646 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
52 | | - | |
| 51 | + | |
| 52 | + | |
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
138 | | - | |
| 138 | + | |
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| |||
414 | 414 | | |
415 | 415 | | |
416 | 416 | | |
417 | | - | |
| 417 | + | |
418 | 418 | | |
419 | 419 | | |
420 | 420 | | |
| |||
907 | 907 | | |
908 | 908 | | |
909 | 909 | | |
910 | | - | |
911 | | - | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
912 | 921 | | |
913 | | - | |
914 | | - | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
915 | 931 | | |
916 | 932 | | |
917 | 933 | | |
| |||
955 | 971 | | |
956 | 972 | | |
957 | 973 | | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
958 | 984 | | |
959 | 985 | | |
960 | 986 | | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
961 | 1003 | | |
962 | 1004 | | |
963 | 1005 | | |
| |||
1009 | 1051 | | |
1010 | 1052 | | |
1011 | 1053 | | |
1012 | | - | |
1013 | | - | |
1014 | | - | |
1015 | | - | |
1016 | | - | |
1017 | | - | |
1018 | | - | |
1019 | | - | |
| 1054 | + | |
1020 | 1055 | | |
1021 | 1056 | | |
1022 | 1057 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
111 | 111 | | |
112 | 112 | | |
113 | | - | |
| 113 | + | |
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
| 127 | + | |
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| |||
134 | 134 | | |
135 | 135 | | |
136 | 136 | | |
137 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
138 | 141 | | |
139 | 142 | | |
140 | 143 | | |
| |||
145 | 148 | | |
146 | 149 | | |
147 | 150 | | |
148 | | - | |
| 151 | + | |
149 | 152 | | |
150 | 153 | | |
151 | 154 | | |
| |||
0 commit comments