diff --git a/README.md b/README.md index 049e05b75..b0cfa3083 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,7 @@ Firstly, you have to exclude the notification module from Mapbox Navigation SDK implementation ('com.ably.tracking:publishing-sdk:1.3.0') // The Mapbox Navigation SDK. -implementation ('com.mapbox.navigation:android:2.7.0') { +implementation ('com.mapbox.navigation:android:2.8.0-rc.2') { exclude group: "com.mapbox.navigation", module: "notification" } ``` diff --git a/publishing-example-app/build.gradle b/publishing-example-app/build.gradle index 8bc216220..05c7d49c9 100644 --- a/publishing-example-app/build.gradle +++ b/publishing-example-app/build.gradle @@ -5,7 +5,7 @@ plugins { id 'org.jlleitschuh.gradle.ktlint' } -final useCrashlytics = project.file('google-services.json').exists(); +final useCrashlytics = project.file('google-services.json').exists() if (useCrashlytics) { apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' @@ -29,7 +29,7 @@ dependencies { implementation 'com.amplifyframework:aws-auth-cognito:1.4.1' implementation 'pub.devrel:easypermissions:3.0.0' // This version needs to be compatible with the "com.mapbox.navigation:core" dependency version from publishing-sdk. - implementation 'com.mapbox.maps:android:10.7.0' + implementation 'com.mapbox.maps:android:10.8.0' if (useCrashlytics) { // The BoM for the Firebase platform (it specifies the versions for Firebase dependencies). diff --git a/publishing-sdk/build.gradle b/publishing-sdk/build.gradle index 6383be27b..ebdf17df6 100644 --- a/publishing-sdk/build.gradle +++ b/publishing-sdk/build.gradle @@ -22,7 +22,7 @@ dependencies { // The MapBox Navigation SDK for Android. // We're not using the pre-built UI components, so just need the core dependency. // https://docs.mapbox.com/android/navigation/overview/ - implementation('com.mapbox.navigation:core:2.7.0') { + implementation('com.mapbox.navigation:core:2.8.0-rc.2') { // We provide a custom trip notification so we exclude the default one. // https://docs.mapbox.com/android/navigation/guides/modularization/#tripnotification exclude group: "com.mapbox.navigation", module: "notification" diff --git a/publishing-sdk/src/main/java/com/ably/tracking/publisher/Mapbox.kt b/publishing-sdk/src/main/java/com/ably/tracking/publisher/Mapbox.kt index 674d7c3a9..4e3ee272e 100644 --- a/publishing-sdk/src/main/java/com/ably/tracking/publisher/Mapbox.kt +++ b/publishing-sdk/src/main/java/com/ably/tracking/publisher/Mapbox.kt @@ -34,7 +34,6 @@ import com.mapbox.navigation.base.trip.model.RouteLegProgress import com.mapbox.navigation.base.trip.model.RouteProgress import com.mapbox.navigation.base.trip.notification.TripNotification import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.core.MapboxNavigationProvider import com.mapbox.navigation.core.arrival.ArrivalObserver import com.mapbox.navigation.core.history.MapboxHistoryReader import com.mapbox.navigation.core.internal.utils.InternalUtils @@ -141,20 +140,44 @@ internal interface Mapbox { } /** - * Singleton object used to count the created instances of [Mapbox] interface implementations ([DefaultMapbox]). - * This is used to check whether we should destroy the [MapboxNavigation] when a [Mapbox] instance is stopped. - * This object is safe to use across multiple threads as it uses an [AtomicInteger] as the counter. + * Singleton object used to hold the created instances of [Mapbox] interface implementations ([DefaultMapbox]). + * Uses reference counting to check whether we should destroy the [MapboxNavigation] when a [Mapbox] instance is stopped. + * This object is safe to use across multiple threads as it uses [synchronized], an [AtomicInteger] as the counter, and [Volatile] annotation on the instance field. */ -private object MapboxInstancesCounter { +private object MapboxInstanceProvider { + + @Volatile + private var mapboxNavigation: MapboxNavigation? = null + private val counter = AtomicInteger(0) - fun increment() { - counter.incrementAndGet() - } - fun decrementAndCheckIfItWasTheLastOne(): Boolean { - val instancesAmount = counter.decrementAndGet() - return instancesAmount == 0 - } + /** + * Call to get a MapboxNavigation instance. When no instance is already created will create a new one using provided options. + * + * @param navigationOptions options to be used if MapboxNavigation needs to be instantiated. + */ + + @Suppress("VisibleForTests") + fun createOrRetrieve(navigationOptions: NavigationOptions): MapboxNavigation = + synchronized(this) { + counter.incrementAndGet() + mapboxNavigation ?: MapboxNavigation(navigationOptions).also { mapboxNavigation = it } + } + + /** + * Call when previously obtained MapboxNavigation instance is no longer used. Will call onDestroy if this was the last reference. + * + * @return A [Boolean] that indicates whether MapboxNavigation was destroyed + */ + fun destroyIfPossible(): Boolean = + synchronized(this) { + val wasLastInstance = counter.decrementAndGet() == 0 + if (wasLastInstance) { + mapboxNavigation?.onDestroy() + mapboxNavigation = null + } + wasLastInstance + } } /** @@ -236,14 +259,8 @@ internal class DefaultMapbox( } runBlocking(mainDispatcher) { - MapboxInstancesCounter.increment() - mapboxNavigation = if (MapboxNavigationProvider.isCreated()) { - logHandler?.v("$TAG Retrieve previously created MapboxNavigation instance") - MapboxNavigationProvider.retrieve() - } else { - logHandler?.v("$TAG Create new MapboxNavigation instance") - MapboxNavigationProvider.create(mapboxBuilder.build()) - } + mapboxNavigation = MapboxInstanceProvider.createOrRetrieve(mapboxBuilder.build()) + logHandler?.v("$TAG obtained MapboxNavigation instance") setupRouteClearingWhenDestinationIsReached() } } @@ -328,9 +345,9 @@ internal class DefaultMapbox( } } } - if (MapboxInstancesCounter.decrementAndCheckIfItWasTheLastOne()) { - logHandler?.v("$TAG Destroy the MapboxNavigation instance") - MapboxNavigationProvider.destroy() + + if (MapboxInstanceProvider.destroyIfPossible()) { + logHandler?.v("$TAG Destroyed the MapboxNavigation instance") } } }