Car-App lifecycle

When integrating Android Auto with your application, an issue you are likely to face, is determining when the car or app is in use. Luckily, the car and app have something in common, The Jetpack Lifecycle Library. To create Lifecycle aware services, we have introduced MapboxNavigationApp which was built on top of the Lifecycle. Refer to Android Auto Lifecycle documentation for questions about Session and Screen Lifecycle.

This guide provides guidance on how to use MapboxNavigationApp and share data between your car and app. MapboxNavigationApp is essentially, a lifecycle reference counter. When an attached lifecycle is CREATED, MapboxNavigationApp will construct an instance of MapboxNavigation and notify all registered MapboxNavigationObserver.

Memory leak alert
The MapboxNavigationApp lifecycle is bound to the Application. If a `MapboxNavigationObserver` holds a reference to an Activity Context or `CarContext`, you are risking a memory leak. Make sure to unregister with MapboxNavigationApp.unregisterObserver and clear subscriptions in `MapboxNavigationObserver.onDetached`.

1. Set up MapboxNavigationApp

You have many options for when or how to setup MapboxNavigationApp. The easiest solution is to add it to your Application.onCreate. The NavigationOptionsProvider will request NavigationOptions when an attached LifecycleOwner is at least CREATED.

if (!MapboxNavigationApp.isSetup()) {
    MapboxNavigationApp.setup {
        NavigationOptions.Builder(context)
            .accessToken("YOUR_ACCESS_TOKEN")
            // additional options
            .build()
    }
}

2. Attach LifecycleOwner

MapboxNavigationApp will create MapboxNavigation when at least one attached LifecycleOwner is CREATED. This accepts any LifecycleOwner, like Activities or Fragments. It will also accept custom LifecycleOwners if you need a custom experience. MapboxNavigationObserver will remain attached until both the car and app are destroyed, this makes for a seamless experience when your users change their Android Auto connection.

In this example, MapboxNavigation will be attached when MyFragment is CREATED.

class MyFragment : Fragment {
  init {
    MapboxNavigationApp.attach(lifecycleOwner = this)
  }
}

In this example, MapboxNavigation will be attached when the MyActivity is RESUMED.

class MyActivity : Activity {
  init {
    lifecycle.addObserver(object : DefaultLifecycleObserver {
      override fun onResume(owner: LifecycleOwner) {
        MapboxNavigationApp.attach(owner)
      }

      override fun onPause(owner: LifecycleOwner) {
        MapboxNavigationApp.detach(owner)
      }
    })
  }
}

Separately, you should attach the Android Auto Session to make MapboxNavigation available in Android Auto. This makes MapboxNavigation available in the car, even when the app has been closed.

class MyCarSession : Session {
    init {
        MapboxNavigationApp.attach(lifecycleOwner = this)
    }
}

3. Registering MapboxNavigationObserver

Register the MapboxNavigationObserver inside Lifecycle callbacks, that will give MapboxNavigationObserver the ability to control a specific definition. Following this pattern will also avoid memory leaks. For each lifecycle state, there is a corresponding destruction event that you can use to unregister the MapboxNavigationObserver.

Registering to the Application
When registering observers to the Application, you do not unregister the observer. The MapboxNavigationApp will call MapboxNavigationObserver.onDetached when the Application is stopped. The Andorid system will destroy the application process and reclaim resources used by the `MapboxNavigationObserver`. You can control when the `MapboxNavigationObserver` is attached with `MapboxNavigationApp.attach(lifecycleOwner = *)`.
MapboxNavigationApp.registerObserverMapboxNavigationApp.unregisterObserver
Application.onCreateunregister is optional
onCreateonDestroy
onStartonStop
onResumeonPause

MapboxNavigationObserver can be registered when the resources are available.

class MyApplication : Application() {
    init {
        // The application context can be found in onAttached through
        // mapboxNavigation.navigationOptions.applicationContext
        MapboxNavigationApp.registerObserver(MyObserver())
    }

    override fun onCreate() {
        super.onCreate()

        // Or you can pass the applicationContext directly after the application is created 
        val observer = MyObserverWithContext(applicationContext)
        MapboxNavigationApp.registerObserver(observer)
    }
}

In this example, MapboxNavigation will be attached when the LifecycleOwner is RESUMED.

private val myObserver = MyMapboxNavigationObserver()

lifecycle.addObserver(object : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        MapboxNavigationApp.registerObserver(myObserver)
    }

    override fun onPause(owner: LifecycleOwner) {
        MapboxNavigationApp.unregisterObserver(myObserver)
    }
})

4. Implement MapboxNavigationObserver

The MapboxNavigationObserver is a lifecycle aware object. You can control when the onAttached/onDetached calls will be triggered with MapboxNavigationApp.setup, MapboxNavigationApp.attach(lifecycleOwner), and MapboxNavigationApp.register(mapboxNavigationObserver). The MapboxNavigationObserver implementation is responsible for declaring what it will do while it is attached. For example, the observer below will register onto the location observer.

class MyMapboxNavigationObserver : MapboxNavigationObserver {
    private val locationObserver = MyLocationObserver()
    val location: Flow<Location> = locationObserver.location()

    override fun onAttached(mapboxNavigation: MapboxNavigation) {
        mapboxNavigation.registerLocationObserver(locationObserver)
    }
    
    override fun onDetached(mapboxNavigation: MapboxNavigation) {
        mapboxNavigation.unregisterLocationObserver(locationObserver)
    }
}