mapbox / mapbox-navigation-android

Mapbox Navigation SDK for Android
https://docs.mapbox.com/android/navigation/overview/
Other
622 stars 319 forks source link

Android Drop-In UI: MapboxNavigation not being initialized in Jetpack Compose #6310

Closed MauResendez closed 1 year ago

MauResendez commented 2 years ago

Android API: 30 implementation 'com.mapbox.navigation:ui-app:2.8.0-beta.3' implementation 'com.mapbox.navigation:ui-dropin:2.8.0-beta.3'

I'm currently attempting to add the NavigationView inside an AndroidView Composable to a Jetpack Compose project.

@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
@Composable
fun Mapbox() {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context -> NavigationView(context, accessToken = context.getString(R.string.access_token))}
    )
}

When the app loads, it shows a NullPointerException error for this line navigation = MapboxNavigationApp.current()!!.

Error: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.dropinjc/com.example.dropinjc.MainActivity}: java.lang.NullPointerException Caused by: java.lang.NullPointerException at com.example.dropinjc.MainActivity.onCreate(MainActivity.kt:50)

I attempted setting up the MapboxNavigationApp to initialize it in the onCreate, but it gave me the same error.

if (!MapboxNavigationApp.isSetup()) {
    MapboxNavigationApp.setup {
        NavigationOptions
            .Builder(applicationContext)
            .accessToken(getString(R.string.access_token))
            .build()
    }
}

Steps to trigger behavior

  1. Starting up the app.

Expected behavior

Initializing the MapboxNavigation when starting the app.

Actual behavior

Crashes from NullPointerException error.

kmadsen commented 1 year ago

Hi @MauResendez! Thanks for cutting an issue and I apologize for the slow response. I just noticed this.

initialize it in the onCreate

The MapboxNavigationinstance becomes available when the NavigationView has been created. @Composable Mapbox lifecycle is started a bit after the onCreate function. Please use the MapboxNavigationObserver in order to access MapboxNavigation from your Activity, do it like this.

This will guarantee that mapboxNavigation is not null.

class MainActivity : ComponentActivity() {

    private val navigationObserver = object : MapboxNavigationObserver {
        override fun onAttached(mapboxNavigation: MapboxNavigation) {
            Log.i("TestingMapbox", "onAttached $mapboxNavigation")
        }

        override fun onDetached(mapboxNavigation: MapboxNavigation) {
            Log.i("TestingMapbox", "onDetached $mapboxNavigation")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Log.i("TestingMapbox", "${MapboxNavigationApp.current()}")
        MapboxNavigationApp.registerObserver(navigationObserver)
        setContent {
            HelloComposeTheme {
                Mapbox()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()

        MapboxNavigationApp.unregisterObserver(navigationObserver)
    }
}

@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
@Composable
fun Mapbox() {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            NavigationView(
                context,
                accessToken = context.getString(R.string.mapbox_access_token)
            )
        }
    )
}

The output is

2022-10-05 10:51:29.319 TestingMapbox: null
2022-10-05 10:51:29.681 TestingMapbox: onAttached com.mapbox.navigation.core.MapboxNavigation@e5f2078
kmadsen commented 1 year ago

Something else I just noticed while testing this.

With Jetpack compose it seems you will need to request location permissions. We have a component that requests location permissions, but it is relying on https://developer.android.com/training/basics/intents/result#register

That launcher will not work if called late in the lifecycle, and compose does not start the NavigationView until the resumed state.

Unable to request location permissions when view is created late in the activity lifecycle. LifecycleOwner com.mapbox.navigation.compose.MainActivity@7a1a63b is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.

abhishek1508 commented 1 year ago

Closing this issue as the original question posted was answered. Please feel free to open another issue if you come across any other problems.