maps: Race race condition if prop is set before styleURL is loaded results in a crash

Describe the bug Race race condition which is happening when <MapboxGL.Camera followUserMode=“course”> prop is set before styleURL is loaded results in a crash on Android. Happens intermittently because sometimes network is faster than rendering.

To Reproduce

          <MapboxGL.MapView
            animated
            ref={c => this.map = c}
            styleURL={this.props.theme.styleURL}
            onUserLocationUpdate={this.onUserLocationUpdate}
            onPress={this.onPress}
            onLongPress={this.onPress}
            logoEnabled={false}
            compassEnabled={false}
            pitchEnabled={false}
            onRegionWillChange={this.onRegionWillChange}
            style={{ flex: 1 }}
            onDidFinishLoadingMap={this.onDidFinishLoadingMap}
            onDidFinishRenderingMap={this.onDidFinishRenderingMap}
            onDidFinishRenderingMapFully={this.onDidFinishRenderingMapFully}
            onDidFinishLoadingStyle={this.onDidFinishLoadingStyle}
          >

              <MapboxGL.Camera
                followUserLocation={this.state.currentTrackingModeIsFollowing}
                followUserMode="course"
                onUserTrackingModeChange={this.onUserTrackingModeChange}
              />
          </MapboxGL.MapView>

Expected behavior Not to crash

Versions (please complete the following information):

  • Platfrom: Android
  • Device: Pixel 2
  • OS: Android API 27
  • SDK Version: I’m using commit id ee78a67e13c27b2258a53849282bc07b5ebc374c
  • React Native Version 0.60.5

Additional context Stack trace

2019-08-28 18:59:21.455 22671-22671/com.myverycoolapp E/unknown:ViewManager: Error while updating prop followUserLocation
    java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46)
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139)
        at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93)
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844)
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952)
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44)
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172)
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
        at android.view.Choreographer.doCallbacks(Choreographer.java:723)
        at android.view.Choreographer.doFrame(Choreographer.java:655)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.NullPointerException: Style in LocationComponentActivationOptions is null. Make sure the Style object isn't null. Wait for the map to fully load before passing the Style object to LocationComponentActivationOptions.
        at com.mapbox.mapboxsdk.location.LocationComponentActivationOptions$Builder.build(LocationComponentActivationOptions.java:229)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.updateLocationLayer(RCTMGLCamera.java:380)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.setUserTrackingMode(RCTMGLCamera.java:491)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.updatedFollowUserMode(RCTMGLCamera.java:510)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.setFollowUserLocation(RCTMGLCamera.java:498)
        at com.mapbox.rctmgl.components.camera.RCTMGLCameraManager.setFollowUserLocation(RCTMGLCameraManager.java:66)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139) 
        at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:790) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
2019-08-28 18:59:21.460 22671-22671/com.myverycoolapp E/unknown:ReactNative: Exception in native call
    com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'followUserLocation' of a view managed by: RCTMGLCamera
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:98)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46)
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139)
        at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93)
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844)
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952)
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44)
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172)
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
        at android.view.Choreographer.doCallbacks(Choreographer.java:723)
        at android.view.Choreographer.doFrame(Choreographer.java:655)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139) 
        at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:790) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
     Caused by: java.lang.NullPointerException: Style in LocationComponentActivationOptions is null. Make sure the Style object isn't null. Wait for the map to fully load before passing the Style object to LocationComponentActivationOptions.
        at com.mapbox.mapboxsdk.location.LocationComponentActivationOptions$Builder.build(LocationComponentActivationOptions.java:229)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.updateLocationLayer(RCTMGLCamera.java:380)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.setUserTrackingMode(RCTMGLCamera.java:491)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.updatedFollowUserMode(RCTMGLCamera.java:510)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.setFollowUserLocation(RCTMGLCamera.java:498)
        at com.mapbox.rctmgl.components.camera.RCTMGLCameraManager.setFollowUserLocation(RCTMGLCameraManager.java:66)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:131) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:46) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139) 
        at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:790) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
2019-08-28 18:59:21.519 22671-22671/com.myverycoolapp D/LocationManager: Tick [174.762890, -36.849760]
2019-08-28 18:59:21.519 22671-22671/com.myverycoolapp D/LocationManager: Listener count 1
2019-08-28 18:59:21.568 1435-1471/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 6742016
2019-08-28 18:59:21.598 1445-1445/? D/SurfaceFlinger: duplicate layer name: changing com.myverycoolapp/com.myverycoolapp.MainActivity to com.myverycoolapp/com.myverycoolapp.MainActivity#1
2019-08-28 18:59:21.603 1435-1471/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 8298496
2019-08-28 18:59:21.617 1435-1471/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 8298496
2019-08-28 18:59:21.624 1435-14292/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 8298496
2019-08-28 18:59:21.625 22671-23004/com.myverycoolapp V/Mbgl-HttpRequest: [HTTP] Request was successful (code = 200).
2019-08-28 18:59:21.713 22671-22671/com.myverycoolapp E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle
    com.mapbox.mapboxsdk.location.LocationComponentNotInitializedException: The LocationComponent has to be activated with one of the LocationComponent#activateLocationComponent overloads before any other methods are invoked.
        at com.mapbox.mapboxsdk.location.LocationComponent.checkActivationState(LocationComponent.java:1546)
        at com.mapbox.mapboxsdk.location.LocationComponent.setLocationComponentEnabled(LocationComponent.java:490)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.updateLocationLayer(RCTMGLCamera.java:385)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.enableLocationComponent(RCTMGLCamera.java:342)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera.access$900(RCTMGLCamera.java:49)
        at com.mapbox.rctmgl.components.camera.RCTMGLCamera$5.onStyleLoaded(RCTMGLCamera.java:335)
        at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:852)
        at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:208)
        at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1215)
        at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:196)
        at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1035)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:325)
        at android.os.Looper.loop(Looper.java:142)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Workaround:

    onDidFinishLoadingStyle = (e) => {
      console.log('onDidFinishLoadingStyle', e)
      this.setState({hasFinishedLoadingStyle:true})
    };

          <MapboxGL.MapView
            onDidFinishLoadingStyle={this.onDidFinishLoadingStyle}
          >

            {this.state.hasFinishedLoadingStyle ? 
              <MapboxGL.Camera
                followUserLocation={this.state.currentTrackingModeIsFollowing}
                followUserMode="course"
                onUserTrackingModeChange={this.onUserTrackingModeChange}
              />
              : null
            }

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 3
  • Comments: 27 (16 by maintainers)

Most upvoted comments

@ferdicus - The problem is that while we get error reports from production, we cannot reproduce the bug locally. I can tell you its around User Location and changing follow modes and how that component is mounted.

Also, while the above work around has largely decreased the bug from occurring, it is still happening.

hey @dorthwein, I can totally relate - however, we have very limited resources here 😞,
especially with something that goes deep into native territory we need the support of the community and that means:

  • solid repro steps
  • test repo to easily reproduce
  • support for clarification questions

I have a hunch this PR could fix this issue.

https://github.com/react-native-mapbox-gl/maps/pull/1619

For those of you who see this bug, the above strategies of wrapping user & camera components in render checks has done tons to decrease the frequency of this bug for us in production, however it does still happen from time to time.

If anyone else runs into this issue something that has worked for us is wrapping the camera in the following.

Just make sure if you allow the user to change the MapStyleURL in any way, that you are first un mounting the camera by setting finishedLoadingStyle to false, then resetting it too true once it has reloaded.

<MapboxGL.MapView onDidFinishLoadingMap={onFinishLoading} onDidFinishLoadingStyle={onDidFinishLoadingStyle}>
     {finishedLoading && finishedLoadingStyle ? <Map.Camera /> : <View />}
</MapboxGL.MapView>