Skip to content

Commit 618c615

Browse files
committed
NAVAND-899: clear geometry caches when routes are cleared
1 parent 3f0dc82 commit 618c615

9 files changed

Lines changed: 211 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ This release depends on, and has been tested with, the following Mapbox dependen
4444
- Mapbox Java `v6.10.0-beta.2` ([release notes](https://github.com/mapbox/mapbox-java/releases/tag/v6.10.0-beta.2))
4545
- Mapbox Android Core `v5.0.2` ([release notes](https://github.com/mapbox/mapbox-events-android/releases/tag/core-5.0.2))
4646

47+
- Added `DecodeUtils#clearCache` to allow trigger route geometry cache clearing in order to reduce memory usage.
48+
- Started clearing route geometry cache when no routes (neither routes used for Active Guidance nor previewed ones) are available.
4749

4850
## Mapbox Navigation SDK 2.9.1 - 11 November, 2022
4951
### Changelog

libnavigation-base/api/current.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,7 @@ package com.mapbox.navigation.base.trip.notification {
17201720
package com.mapbox.navigation.base.utils {
17211721

17221722
public final class DecodeUtils {
1723+
method public static void clearCache();
17231724
method public static com.mapbox.geojson.LineString completeGeometryToLineString(com.mapbox.api.directions.v5.models.DirectionsRoute);
17241725
method public static java.util.List<com.mapbox.geojson.Point> completeGeometryToPoints(com.mapbox.api.directions.v5.models.DirectionsRoute);
17251726
method public static com.mapbox.geojson.LineString stepGeometryToLineString(com.mapbox.api.directions.v5.models.DirectionsRoute, com.mapbox.api.directions.v5.models.LegStep legStep);

libnavigation-base/src/main/java/com/mapbox/navigation/base/utils/DecodeUtils.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ object DecodeUtils {
122122
return stepsGeometryDecodeCache.getOrDecode(legStep.geometry(), precision)
123123
}
124124

125+
@JvmStatic
126+
fun clearCache() {
127+
synchronized(stepsGeometryDecodeCache) {
128+
cachedRoutes.clear()
129+
stepsGeometryDecodeCache.evictAll()
130+
stepsGeometryDecodeCache.resize(1)
131+
}
132+
completeGeometryDecodeCache.evictAll()
133+
}
134+
125135
/**
126136
* todo Remove inline references to RouteOptions in favor of taking geometry type as an argument or expose the extensions on top of NavigationRoute instead.
127137
*/

libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class MapboxNavigation @VisibleForTesting internal constructor(
259259
)
260260
private val tripNotificationInterceptorOwner = TripNotificationInterceptorOwner()
261261
private val internalRoutesObserver: RoutesObserver
262+
private val routesCacheClearer = NavigationComponentProvider.createRoutesCacheClearer()
262263
private val internalOffRouteObserver: OffRouteObserver
263264
private val internalFallbackVersionsObserver: FallbackVersionsObserver
264265
private val routeAlternativesController: RouteAlternativesController
@@ -569,6 +570,7 @@ class MapboxNavigation @VisibleForTesting internal constructor(
569570
tripSession.registerOffRouteObserver(internalOffRouteObserver)
570571
tripSession.registerFallbackVersionsObserver(internalFallbackVersionsObserver)
571572
registerRoutesObserver(internalRoutesObserver)
573+
setUpRouteCacheClearer()
572574

573575
roadObjectsStore = RoadObjectsStore(navigator)
574576
graphAccessor = GraphAccessor(navigator)
@@ -1991,6 +1993,12 @@ class MapboxNavigation @VisibleForTesting internal constructor(
19911993
routeScope = createChildScope()
19921994
}
19931995

1996+
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
1997+
private fun setUpRouteCacheClearer() {
1998+
registerRoutesObserver(routesCacheClearer)
1999+
registerRoutesPreviewObserver(routesCacheClearer)
2000+
}
2001+
19942002
private companion object {
19952003

19962004
@Volatile

libnavigation-core/src/main/java/com/mapbox/navigation/core/NavigationComponentProvider.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,6 @@ internal object NavigationComponentProvider {
114114
RouteProgressDataProvider()
115115

116116
fun createEVDataHolder(): EVDataHolder = EVDataHolder()
117+
118+
fun createRoutesCacheClearer(): RoutesCacheClearer = RoutesCacheClearer()
117119
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.mapbox.navigation.core
2+
3+
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
4+
import com.mapbox.navigation.base.route.NavigationRoute
5+
import com.mapbox.navigation.base.utils.DecodeUtils
6+
import com.mapbox.navigation.core.directions.session.RoutesObserver
7+
import com.mapbox.navigation.core.directions.session.RoutesUpdatedResult
8+
import com.mapbox.navigation.core.preview.RoutesPreviewObserver
9+
import com.mapbox.navigation.core.preview.RoutesPreviewUpdate
10+
11+
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
12+
internal class RoutesCacheClearer : RoutesObserver, RoutesPreviewObserver {
13+
14+
private var currentActiveRoutes: List<NavigationRoute> = emptyList()
15+
private var currentPreviewsRoutes: List<NavigationRoute>? = null
16+
17+
override fun onRoutesChanged(result: RoutesUpdatedResult) {
18+
currentActiveRoutes = result.navigationRoutes
19+
if (result.navigationRoutes.isEmpty() && currentPreviewsRoutes.isNullOrEmpty()) {
20+
DecodeUtils.clearCache()
21+
}
22+
}
23+
24+
override fun routesPreviewUpdated(update: RoutesPreviewUpdate) {
25+
currentPreviewsRoutes = update.routesPreview?.routesList
26+
if (update.routesPreview?.routesList.isNullOrEmpty() && currentActiveRoutes.isEmpty()) {
27+
DecodeUtils.clearCache()
28+
}
29+
}
30+
}

libnavigation-core/src/test/java/com/mapbox/navigation/core/MapboxNavigationBaseTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ internal open class MapboxNavigationBaseTest {
102102
val threadController = mockk<ThreadController>(relaxed = true)
103103
val routeProgressDataProvider = mockk<RouteProgressDataProvider>(relaxed = true)
104104
val routesPreviewController = mockk<RoutesPreviewController>(relaxed = true)
105+
val routesCacheClearer = mockk<RoutesCacheClearer>(relaxed = true)
105106

106107
val applicationContext: Context = mockk(relaxed = true) {
107108
every { inferDeviceLocale() } returns Locale.US
@@ -211,6 +212,7 @@ internal open class MapboxNavigationBaseTest {
211212
every {
212213
NavigationComponentProvider.createRoutesPreviewController(any())
213214
} returns routesPreviewController
215+
every { NavigationComponentProvider.createRoutesCacheClearer() } returns routesCacheClearer
214216

215217
every {
216218
navigator.create(

libnavigation-core/src/test/java/com/mapbox/navigation/core/MapboxNavigationTest.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,18 @@ internal class MapboxNavigationTest : MapboxNavigationBaseTest() {
140140
@Test
141141
fun init_routesObs_internalRouteObs_navigationSession_and_TelemetryLocAndProgressDispatcher() {
142142
createMapboxNavigation()
143-
verify(exactly = 2) { directionsSession.registerRoutesObserver(any()) }
143+
// + 1 for navigationSession
144+
// + 1 for routesCacheClearer
145+
verify(exactly = 3) { directionsSession.registerRoutesObserver(any()) }
146+
}
147+
148+
@Test
149+
fun init_registersRoutesCacheClearerAsObservers() {
150+
createMapboxNavigation()
151+
verify(exactly = 1) {
152+
directionsSession.registerRoutesObserver(routesCacheClearer)
153+
routesPreviewController.registerRoutesPreviewObserver(routesCacheClearer)
154+
}
144155
}
145156

146157
@Test
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package com.mapbox.navigation.core
2+
3+
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
4+
import com.mapbox.navigation.base.utils.DecodeUtils
5+
import com.mapbox.navigation.core.directions.session.RoutesUpdatedResult
6+
import com.mapbox.navigation.core.preview.RoutesPreview
7+
import com.mapbox.navigation.core.preview.RoutesPreviewUpdate
8+
import io.mockk.clearStaticMockk
9+
import io.mockk.every
10+
import io.mockk.mockk
11+
import io.mockk.mockkStatic
12+
import io.mockk.unmockkStatic
13+
import io.mockk.verify
14+
import org.junit.After
15+
import org.junit.Before
16+
import org.junit.Test
17+
18+
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
19+
class RoutesCacheClearerTest {
20+
21+
private val sut = RoutesCacheClearer()
22+
23+
@Before
24+
fun setUp() {
25+
mockkStatic(DecodeUtils::class)
26+
}
27+
28+
@After
29+
fun tearDown() {
30+
unmockkStatic(DecodeUtils::class)
31+
}
32+
33+
@Test
34+
fun onRoutesChanged_emptyNoPreviewedRoutes() {
35+
sut.onRoutesChanged(RoutesUpdatedResult(emptyList(), ""))
36+
37+
verify(exactly = 1) { DecodeUtils.clearCache() }
38+
}
39+
40+
@Test
41+
fun onRoutesChanged_nonEmptyNoPreviewedRoutes() {
42+
sut.onRoutesChanged(RoutesUpdatedResult(listOf(mockk()), ""))
43+
44+
verify(exactly = 0) { DecodeUtils.clearCache() }
45+
}
46+
47+
@Test
48+
fun onRoutesChanged_emptyHasPreviewedRoutes() {
49+
sut.routesPreviewUpdated(
50+
RoutesPreviewUpdate("", RoutesPreview(listOf(mockk()), emptyList(), listOf(mockk()), 0))
51+
)
52+
clearStaticMockk(DecodeUtils::class)
53+
54+
sut.onRoutesChanged(RoutesUpdatedResult(emptyList(), ""))
55+
56+
verify(exactly = 0) { DecodeUtils.clearCache() }
57+
}
58+
59+
@Test
60+
fun onRoutesChanged_emptyClearedPreviewedRoutes() {
61+
sut.routesPreviewUpdated(
62+
RoutesPreviewUpdate("", RoutesPreview(listOf(mockk()), emptyList(), listOf(mockk()), 0))
63+
)
64+
sut.routesPreviewUpdated(
65+
RoutesPreviewUpdate("", mockk { every { routesList } returns emptyList() })
66+
)
67+
clearStaticMockk(DecodeUtils::class)
68+
69+
sut.onRoutesChanged(RoutesUpdatedResult(emptyList(), ""))
70+
71+
verify(exactly = 1) { DecodeUtils.clearCache() }
72+
}
73+
74+
@Test
75+
fun routesPreviewUpdated_nullPreviewAndNoActiveRoutes() {
76+
sut.routesPreviewUpdated(RoutesPreviewUpdate("", null))
77+
78+
verify(exactly = 1) { DecodeUtils.clearCache() }
79+
}
80+
81+
@Test
82+
fun routesPreviewUpdated_emptyRoutesAndNoActiveRoutes() {
83+
sut.routesPreviewUpdated(
84+
RoutesPreviewUpdate("", mockk { every { routesList } returns emptyList() })
85+
)
86+
87+
verify(exactly = 1) { DecodeUtils.clearCache() }
88+
}
89+
90+
@Test
91+
fun routesPreviewUpdated_nonEmptyRoutesAndNoActiveRoutes() {
92+
sut.routesPreviewUpdated(
93+
RoutesPreviewUpdate("", RoutesPreview(listOf(mockk()), emptyList(), listOf(mockk()), 0))
94+
)
95+
96+
verify(exactly = 0) { DecodeUtils.clearCache() }
97+
}
98+
99+
@Test
100+
fun routesPreviewUpdated_nullPreviewAndHasActiveRoutes() {
101+
sut.onRoutesChanged(RoutesUpdatedResult(listOf(mockk()), ""))
102+
clearStaticMockk(DecodeUtils::class)
103+
104+
sut.routesPreviewUpdated(RoutesPreviewUpdate("", null))
105+
106+
verify(exactly = 0) { DecodeUtils.clearCache() }
107+
}
108+
109+
@Test
110+
fun routesPreviewUpdated_emptyRoutesAndHasActiveRoutes() {
111+
sut.onRoutesChanged(RoutesUpdatedResult(listOf(mockk()), ""))
112+
clearStaticMockk(DecodeUtils::class)
113+
114+
sut.routesPreviewUpdated(
115+
RoutesPreviewUpdate("", mockk { every { routesList } returns emptyList() })
116+
)
117+
118+
verify(exactly = 0) { DecodeUtils.clearCache() }
119+
}
120+
121+
@Test
122+
fun routesPreviewUpdated_nullPreviewAndClearedActiveRoutes() {
123+
sut.onRoutesChanged(RoutesUpdatedResult(listOf(mockk()), ""))
124+
sut.onRoutesChanged(RoutesUpdatedResult(emptyList(), ""))
125+
clearStaticMockk(DecodeUtils::class)
126+
127+
sut.routesPreviewUpdated(RoutesPreviewUpdate("", null))
128+
129+
verify(exactly = 1) { DecodeUtils.clearCache() }
130+
}
131+
132+
@Test
133+
fun routesPreviewUpdated_emptyRoutesAndClearedActiveRoutes() {
134+
sut.onRoutesChanged(RoutesUpdatedResult(listOf(mockk()), ""))
135+
sut.onRoutesChanged(RoutesUpdatedResult(emptyList(), ""))
136+
clearStaticMockk(DecodeUtils::class)
137+
138+
sut.routesPreviewUpdated(
139+
RoutesPreviewUpdate("", mockk { every { routesList } returns emptyList() })
140+
)
141+
142+
verify(exactly = 1) { DecodeUtils.clearCache() }
143+
}
144+
}

0 commit comments

Comments
 (0)