Skip to content

Commit 722ce60

Browse files
committed
fix(markers): cancel stale icon jobs and guard pending marker updates
1 parent 8039422 commit 722ce60

4 files changed

Lines changed: 41 additions & 16 deletions

File tree

android/src/main/java/com/rngooglemapsplus/MapMarkerBuilder.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ class MapMarkerBuilder(
256256
m: RNMarker,
257257
onReady: (BitmapDescriptor?) -> Unit,
258258
) {
259-
jobsById[m.id]?.cancel()
259+
cancelIconJob(m.id)
260260

261261
m.iconSvg ?: return onReady(null)
262262

@@ -275,6 +275,7 @@ class MapMarkerBuilder(
275275
if (renderResult?.bitmap == null) {
276276
withContext(Dispatchers.Main) {
277277
ensureActive()
278+
jobsById.remove(m.id)
278279
onReady(createFallbackDescriptor())
279280
}
280281
return@launch
@@ -290,34 +291,34 @@ class MapMarkerBuilder(
290291

291292
withContext(Dispatchers.Main) {
292293
ensureActive()
294+
jobsById.remove(m.id)
293295
onReady(desc)
294296
}
295297
} catch (e: OutOfMemoryError) {
296298
mapErrorHandler.report(RNMapErrorCode.MARKER_ICON_BUILD_FAILED, "markerId=${m.id} buildIconAsync out of memory", e)
297299
clearIconCache()
298300
withContext(Dispatchers.Main) {
299301
ensureActive()
302+
jobsById.remove(m.id)
300303
onReady(createFallbackDescriptor())
301304
}
302305
} catch (_: CancellationException) {
303-
withContext(Dispatchers.Main) {
304-
ensureActive()
305-
onReady(createFallbackDescriptor())
306-
}
306+
// cancelled
307307
} catch (t: Throwable) {
308308
mapErrorHandler.report(RNMapErrorCode.MARKER_ICON_BUILD_FAILED, "markerId=${m.id} buildIconAsync failed", t)
309309
withContext(Dispatchers.Main) {
310310
ensureActive()
311+
jobsById.remove(m.id)
311312
onReady(createFallbackDescriptor())
312313
}
313-
} finally {
314-
jobsById.remove(m.id)
315314
}
316315
}
317316

318317
jobsById[m.id] = job
319318
}
320319

320+
fun hasIconJob(id: String): Boolean = jobsById.containsKey(id)
321+
321322
fun cancelIconJob(id: String) {
322323
jobsById[id]?.cancel()
323324
jobsById.remove(id)

android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,18 @@ class RNGoogleMapsPlusView(
170170
}
171171

172172
!prev.markerEquals(next) -> {
173-
view.updateMarker(id) { marker ->
174-
markerBuilder.update(prev, next, marker)
173+
if (markerBuilder.hasIconJob(id)) {
174+
markerBuilder.buildIconAsync(next) { icon ->
175+
view.addMarker(
176+
id,
177+
markerBuilder.build(next, icon),
178+
MarkerTag(id = id, iconSvg = next.infoWindowIconSvg),
179+
)
180+
}
181+
} else {
182+
view.updateMarker(id) { marker ->
183+
markerBuilder.update(prev, next, marker)
184+
}
175185
}
176186
}
177187
}

ios/MapMarkerBuilder.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ final class MapMarkerBuilder {
159159
_ m: RNMarker,
160160
onReady: @escaping (UIImage?) -> Void
161161
) {
162-
tasks[m.id]?.cancel()
162+
cancelIconTask(m.id)
163163

164164
guard let iconSvg = m.iconSvg else {
165165
onReady(nil)
@@ -176,16 +176,14 @@ final class MapMarkerBuilder {
176176

177177
let task = Task(priority: .userInitiated) { [weak self] in
178178
guard let self else { return }
179-
defer {
180-
Task { @MainActor in self.tasks.removeValue(forKey: m.id) }
181-
}
182179

183180
let renderResult = self.renderUIImage(iconSvg, m.id, scale)
184181
guard !Task.isCancelled else { return }
185182

186183
guard let renderResult = renderResult else {
187184
await MainActor.run {
188185
guard !Task.isCancelled else { return }
186+
self.tasks.removeValue(forKey: m.id)
189187
onReady(self.createFallbackUIImage())
190188
}
191189
return
@@ -197,13 +195,18 @@ final class MapMarkerBuilder {
197195

198196
await MainActor.run {
199197
guard !Task.isCancelled else { return }
198+
self.tasks.removeValue(forKey: m.id)
200199
onReady(renderResult.image)
201200
}
202201
}
203202

204203
tasks[m.id] = task
205204
}
206205

206+
func hasIconTask(_ id: String) -> Bool {
207+
tasks[id] != nil
208+
}
209+
207210
func cancelIconTask(_ id: String) {
208211
tasks[id]?.cancel()
209212
tasks.removeValue(forKey: id)
@@ -311,6 +314,9 @@ final class MapMarkerBuilder {
311314
return autoreleasepool { () -> (image: UIImage, isFallback: Bool)? in
312315
guard !Task.isCancelled else { return nil }
313316

317+
CATransaction.begin()
318+
defer { CATransaction.commit() }
319+
314320
guard let svgImg = SVGKImage(data: data) else {
315321
mapErrorHandler.report(RNMapErrorCode.markerIconBuildFailed, "markerId=\(markerId) icon: SVGKImage init failed")
316322
return (createFallbackUIImage(), true)

ios/RNGoogleMapsPlusView.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,17 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
127127
for (id, next) in nextById {
128128
if let prev = prevById[id] {
129129
if !prev.markerEquals(next) {
130-
self.impl.updateMarker(id: id) { [weak self] m in
131-
guard let self else { return }
132-
self.markerBuilder.update(prev, next, m)
130+
if self.markerBuilder.hasIconTask(id) {
131+
self.markerBuilder.buildIconAsync(next) { [weak self] icon in
132+
guard let self else { return }
133+
let marker = self.markerBuilder.build(next, icon: icon)
134+
self.impl.addMarker(id: id, marker: marker)
135+
}
136+
} else {
137+
self.impl.updateMarker(id: id) { [weak self] m in
138+
guard let self else { return }
139+
self.markerBuilder.update(prev, next, m)
140+
}
133141
}
134142
}
135143
} else {

0 commit comments

Comments
 (0)