Skip to content

Commit

Permalink
Create a delegate for MapboxNavigation called `requireMapboxNavigat…
Browse files Browse the repository at this point in the history
…ion` (#6233)

* Create a delegate for MapboxNavigation

* Make requireMapboxNavigation attach during initialization
  • Loading branch information
kmadsen authored Sep 6, 2022
1 parent 847f8a9 commit e3e78f4
Show file tree
Hide file tree
Showing 8 changed files with 628 additions and 113 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Mapbox welcomes participation and contributions from everyone.
## Unreleased
#### Features
- Improved the route refresh feature to also refresh _closures_ (`RouteLeg#closures`). [#6274](https://github.com/mapbox/mapbox-navigation-android/pull/6274)

- Added `requireMapboxNavigation` to offer a simple way to use `MapboxNavigationApp`. [#6233](https://github.com/mapbox/mapbox-navigation-android/pull/6233)
#### Bug fixes and improvements

## Mapbox Navigation SDK 2.8.0-beta.2 - 01 September, 2022
Expand Down
4 changes: 4 additions & 0 deletions libnavigation-core/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ package com.mapbox.navigation.core.lifecycle {
method public com.mapbox.navigation.base.options.NavigationOptions createNavigationOptions();
}

public final class RequireMapboxNavigation {
method @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public static kotlin.properties.ReadOnlyProperty<java.lang.Object,com.mapbox.navigation.core.MapboxNavigation> requireMapboxNavigation(androidx.lifecycle.LifecycleOwner, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onCreatedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onStartedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onResumedObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit>? onInitialize = null);
}

}

package com.mapbox.navigation.core.navigator {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
@file:JvmName("RequireMapboxNavigation")

package com.mapbox.navigation.core.lifecycle

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp.lifecycleOwner
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
* Extension function to make it simple to create the [RequireMapboxNavigationDelegate].
* Below are a couple examples of how you may use the delegate.
*
* Default can be used when [MapboxNavigationApp] is setup elsewhere.
* ```
* val mapboxNavigation by requireMapboxNavigation()
* ```
*
* Initialize the [MapboxNavigationApp] when you are ready to use it
* ```
* val mapboxNavigation by requireMapboxNavigation {
* MapboxNavigationApp.setup(..)
* }
* ```
*
* Register subscriptions and setup MapboxNavigationApp
* ```
* private val mapboxNavigation by requireMapboxNavigation(
* onResumedObserver = object : MapboxNavigationObserver {
* override fun onAttached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.registerLocationObserver(locationObserver)
* mapboxNavigation.registerRoutesObserver(routesObserver)
* }
* override fun onDetached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.unregisterLocationObserver(locationObserver)
* mapboxNavigation.unregisterRoutesObserver(routesObserver)
* }
* }
* ) {
* MapboxNavigationApp.setup(
* NavigationOptions.Builder(this)
* .accessToken(accessToken)
* .build()
* )
* }
* ```
*
* @see [RequireMapboxNavigationDelegate] for more details.
*/
@ExperimentalPreviewMapboxNavigationAPI
fun LifecycleOwner.requireMapboxNavigation(
onCreatedObserver: MapboxNavigationObserver? = null,
onStartedObserver: MapboxNavigationObserver? = null,
onResumedObserver: MapboxNavigationObserver? = null,
onInitialize: (() -> Unit)? = null,
): ReadOnlyProperty<Any, MapboxNavigation> = RequireMapboxNavigationDelegate(
lifecycleOwner = this,
onCreatedObserver = onCreatedObserver,
onStartedObserver = onStartedObserver,
onResumedObserver = onResumedObserver,
onInitialize = onInitialize
)

/**
* Attaches a [LifecycleOwner] to [MapboxNavigationApp] and provides access to [MapboxNavigation].
*
* You can choose to call [MapboxNavigationApp.setup] in the [onInitialize]. You can also setup in
* the onCreate calls, or any call that happens before this delegate is accessed. The delegate will
* crash if accessed when the app is not setup or an attached lifecycle has not been created.
*
* You can use the observers parameter to setup any subscriptions. This is important because the
* [MapboxNavigation] instance can be re-created with [MapboxNavigationApp.disable], or if all
* [MapboxNavigationApp.attach] lifecycles are destroyed.
*
* @param lifecycleOwner: LifecycleOwner
* @param onCreatedObserver registered to the [Lifecycle.State.CREATED] lifecycle
* @param onStartedObserver registered to the [Lifecycle.State.STARTED] lifecycle
* @param onResumedObserver registered to the [Lifecycle.State.RESUMED] lifecycle
* @param onInitialize called when the [lifecycleOwner] is [Lifecycle.State.CREATED]
*/
internal class RequireMapboxNavigationDelegate(
lifecycleOwner: LifecycleOwner,
private val onCreatedObserver: MapboxNavigationObserver? = null,
private val onStartedObserver: MapboxNavigationObserver? = null,
private val onResumedObserver: MapboxNavigationObserver? = null,
private val onInitialize: (() -> Unit)? = null
) : ReadOnlyProperty<Any, MapboxNavigation> {

private val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
onInitialize?.invoke()
onCreatedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onDestroy(owner: LifecycleOwner) {
onCreatedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onStart(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onStop(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onResume(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onPause(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}
}

init {
MapboxNavigationApp.attach(lifecycleOwner)
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}

/**
* Returns an instance of [MapboxNavigation]. If [MapboxNavigationApp.isSetup] is false after
* all observers and initializers, this property getter will crash.
*
* @param thisRef - the [LifecycleOwner] that needs access to [MapboxNavigation].
* @param property - ignored
*/
override fun getValue(thisRef: Any, property: KProperty<*>): MapboxNavigation {
val mapboxNavigation = MapboxNavigationApp.current()
checkNotNull(mapboxNavigation) {
"MapboxNavigation cannot be null. Ensure that MapboxNavigationApp is setup and an" +
" attached lifecycle is at least CREATED."
}
return mapboxNavigation
}
}
Loading

0 comments on commit e3e78f4

Please sign in to comment.