Repository navigation
Description
Mapbox Implementation
Mapbox
Mapbox Version
default
React Native Version
0.85.3 (New Architecture, bridgeless)
Platform
Android
@rnmapbox/maps version
10.3.1 (same code on main / v10.3.11)
Standalone component to reproduce
import React from 'react';
import Mapbox from '@rnmapbox/maps';
export default function App() {
return (
<Mapbox.MapView style={{ flex: 1 }}>
<Mapbox.Camera followUserLocation followZoomLevel={16} />
<Mapbox.UserLocation
visible={false}
onUpdate={loc => console.log('onUpdate', loc.coords.latitude, loc.coords.longitude)}
/>
</Mapbox.MapView>
);
}Observed behavior and steps to reproduce
- Run an app with the component above.
onUpdatefires as expected. - Have something keep the app process alive without the Activity, e.g. a running foreground service.
- Leave the app in a way that destroys the Activity while the service keeps the process alive.
- Reopen the app. A new Activity is created in the same process.
Seen on a Samsung Galaxy S23+ running Android 16.
5. onUpdate never fires again, and the map never locates. No location request reaches the OS: adb shell dumpsys location shows no registration from the map. This holds until the process is killed.
In our logs, ReactHost.onHostDestroy fires in the same pid that later remounts the map.
This looks like the same symptom as #3965 ("UserLocation stops updating after restarting app with background foregroundService on Android"), which was closed as not planned without a root cause. Here is one.
Expected behavior
Location updates resume when the new Activity resumes, as they do after a plain pause/resume.
Notes / preliminary analysis
Two problems in android/.../modules/RNMBXLocationModule.kt and location/LocationManager.kt:
-
onHostDestroypermanently disables the process-wideLocationManager.onHostDestroycallslocationManager?.destroy(), which disposes the engine and setsnStarts = -1000.LocationManageris a singleton that outlives the Activity, andstartCounted()only enables the engine whennStarts == 1. From then on nostart()can re-enable it for the life of the process.onHostDestroyfires on every Activity destroy, not only on React instance teardown, so a surviving process (foreground service, "Don't keep activities", system reclaiming a background Activity) ends up with a dead location feed. The location puck shares the same counter (LocationComponentManager), so it is affected too. -
start()counts twice.start()callslocationManager?.startCounted()and thenstartLocationManager(), which callsstartCounted()again.stop()→stopLocationManager()callsstopCounted()once. The count can therefore never return to 0, sostop()never disposes the engine.
We're applying the patch below with patch-package. It compiles; in our app the screen that hit this now uses a different location source, so we haven't exercised the patched path on a device yet.
override fun onHostDestroy() {
- locationManager?.destroy()
+ // The Activity can be destroyed while the process (and this module) lives on.
+ // Pause instead; the next Activity's onHostResume re-enables. Teardown is in invalidate().
+ locationManager?.pause()
}
...
+ override fun invalidate() {
+ reactApplicationContext.removeLifecycleEventListener(lifecycleEventListener)
+ stopLocationManager()
+ super.invalidate()
+ }
+
@ReactMethod
override fun start(minDisplacement: Double) {
- isEnabled = true
mMinDisplacement = minDisplacement.toFloat()
- locationManager?.startCounted()
+ // One count per enabled module, matching the single stopCounted() in stop().
+ if (isEnabled) return
+ isEnabled = true
startLocationManager()
}Additional links and references
- [Bug]: UserLocation stops updating after restarting app with background foregroundService on Android #3965 (same symptom, closed not planned)
Activity
fix(android): keep UserLocation updating after the Activity is destro…