@@ -74,7 +74,7 @@ public class NavModule extends NativeNavModuleSpec
7474 private NavViewManager mNavViewManager ;
7575 private final CopyOnWriteArrayList <NavigationReadyListener > mNavigationReadyListeners =
7676 new CopyOnWriteArrayList <>();
77- private boolean mIsListeningRoadSnappedLocation = false ;
77+ private volatile boolean mIsListeningRoadSnappedLocation = false ;
7878 private LocationListener mLocationListener ;
7979 private Navigator .ArrivalListener mArrivalListener ;
8080 private Navigator .RouteChangedListener mRouteChangedListener ;
@@ -167,8 +167,6 @@ public void cleanup(final Promise promise) {
167167 }
168168
169169 mIsListeningRoadSnappedLocation = false ;
170- removeLocationListener ();
171- removeNavigationListeners ();
172170 mWaypoints .clear ();
173171
174172 for (NavigationReadyListener listener : mNavigationReadyListeners ) {
@@ -178,6 +176,11 @@ public void cleanup(final Promise promise) {
178176 final Navigator navigator = mNavigator ;
179177 UiThreadUtil .runOnUiThread (
180178 () -> {
179+ // Remove listeners on UI thread to serialize with callback dispatch.
180+ // This reduces the chance of triggering a race condition in the Navigation SDK
181+ // where callbacks may still be in-flight during removal.
182+ removeLocationListener ();
183+ removeNavigationListeners ();
181184 navigator .clearDestinations ();
182185 navigator .stopGuidance ();
183186 navigator .getSimulator ().unsetUserLocation ();
@@ -939,20 +942,31 @@ public void resetTermsAccepted(final Promise promise) {
939942
940943 @ Override
941944 public void startUpdatingLocation (final Promise promise ) {
942- registerLocationListener ();
943945 mIsListeningRoadSnappedLocation = true ;
944- promise .resolve (null );
946+ // Register listener on UI thread to serialize with callback dispatch and allow
947+ // safe remove-and-recreate.
948+ UiThreadUtil .runOnUiThread (
949+ () -> {
950+ registerLocationListener ();
951+ promise .resolve (null );
952+ });
945953 }
946954
947955 @ Override
948956 public void stopUpdatingLocation (final Promise promise ) {
949957 mIsListeningRoadSnappedLocation = false ;
950- removeLocationListener ();
951- promise .resolve (null );
958+ // Remove the listener on UI thread to serialize with callback dispatch.
959+ // This avoids the race condition in the Navigation SDK.
960+ UiThreadUtil .runOnUiThread (
961+ () -> {
962+ removeLocationListener ();
963+ promise .resolve (null );
964+ });
952965 }
953966
954967 private void registerLocationListener () {
955- // Unregister existing location listener if available.
968+ // Remove existing listener first, then recreate. This is safe when called
969+ // from UI thread as it serializes with callback dispatch.
956970 removeLocationListener ();
957971
958972 if (mRoadSnappedLocationProvider != null ) {
0 commit comments