mapbox / mapbox/mapbox-navigation-android
com.mapbox.navigation.ui:1.6.1 crash during configurations change
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 651
- Forks
- 321
- PR merge metrics
- No merged PRs in 30d
Description
**Android API: 29+**
**com.mapbox.navigation.ui:1.6.1**
### Steps to trigger behavior
1. Create a `com.mapbox.navigation.ui.NavigationView` in a new fragment
2. Wait for the night, so the device will go into a dark mode(don't listen for configurations changes in the activity)
3. Call to start navigation after the fragment was recreated
### Expected behavior
No crashing
### Actual behavior
A crash
```
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.mapbox.navigation.ui.NavigationViewEventDispatcher.onNavigationFinished()' on a null object reference
at com.mapbox.navigation.ui.NavigationViewModel$3.onSessionStateChanged(NavigationViewModel.java:531)
at com.mapbox.navigation.core.trip.session.MapboxTripSession.registerStateObserver(MapboxTripSession.kt:309)
at com.mapbox.navigation.core.MapboxNavigation.registerTripSessionStateObserver(MapboxNavigation.kt:519)
at com.mapbox.navigation.ui.NavigationViewModel.addNavigationListeners(NavigationViewModel.java:448)
at com.mapbox.navigation.ui.NavigationViewModel.initializeNavigation(NavigationViewModel.java:438)
at com.mapbox.navigation.ui.NavigationViewModel.initialize(NavigationViewModel.java:220)
at com.mapbox.navigation.ui.NavigationView.initializeNavigation(NavigationView.java:935)
at com.mapbox.navigation.ui.NavigationView.startNavigation(NavigationView.java:497)
```
### Why do I think this is happening?
During fragment recreation, a new view is created before the old view is destroyed.
After the old view is destroyed it calls to `com.mapbox.navigation.ui.NavigationViewModel.onDestroy`. It sets the `navigationViewEventDispatcher` to `null`.
When the new view calls to `startNavigation` the app is crashing because `navigationViewEventDispatcher` is `null`.
The `NavigationViewModel` is using an activity life cycle, so you should not couple it with the View life cycle. I bet this causes a bunch of other bugs as well.
## A workaround
Before starting navigation, check for this bug and attempt to reinitialize the view
### Check for the bug
```
fun isNavigationViewEventDispatcherNullBug(): Boolean {
val navigationViewModel =
ViewModelProvider(requireActivity()).get(NavigationViewModel::class.java)
val field = navigationViewModel.javaClass.getDeclaredField("navigationViewEventDispatcher")
field.isAccessible = true
return field.get(navigationViewModel) == null
}
```
### Reinitialize the view
```
fun reinitializeNavigationView() {
val methods = NavigationView::class.java.declaredMethods
methods.filter {
arrayOf(
"initializeNavigationEventDispatcher",
"initializeInstructionListener",
"initializeSummaryBottomSheet"
).contains(it.name)
}.forEach {
it.isAccessible = true
it.invoke(navigationView)
}
}
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing NavigationViewModel.onDestroy, initializeNavigation, and addNavigationListeners, then compare their activity and view lifecycle behavior during Fragment recreation. Reproduce the dark-mode configuration change with NavigationView and startNavigation. Done means the recreated view starts navigation without the navigationViewEventDispatcher null crash.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100