Description
Dynamically adding SymbolLayers and combining existing and dynamical filters results in an exception on Android devices.
E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle
java.lang.ClassCastException: com.mapbox.mapboxsdk.style.layers.FillLayer cannot be cast to com.mapbox.mapboxsdk.style.layers.SymbolLayer
To Reproduce
Steps to reproduce the behavior.
Example:
// React
import React, {Component} from 'react';
import {
StyleSheet,
View,
Dimensions,
} from 'react-native';
// Navigation
import {StackNavigationProp} from '@react-navigation/stack';
import {StackParamList} from '../navigators/Navigator';
import {RouteProp} from '@react-navigation/native';
// Data Models
import Survey from './../../models/data_models/Survey';
import SurveyLocation from './../../models/data_models/SurveyLocation';
// Components
import LMConstants from './../../constants/LMConstants';
// Third Party Libraries
import MapboxGL from '@react-native-mapbox-gl/maps';
// Set the access token for mapbox surveyapp project
MapboxGL.setAccessToken(
'<HIDDEN>',
);
interface MapScreenprops {
navigation: StackNavigationProp<StackParamList, 'MapScreen'>;
route: RouteProp<StackParamList, 'MapScreen'>;
Surveys: Map<string, Survey>;
Locations: Map<string, SurveyLocation>;
}
interface MapScreenstate {
mapStylesURL: string;
zoomLevel: number;
mapCenter: number[];
currentFloor: number;
layerIDsAndFilters: Map<string, string>;
}
class MapScreen extends Component<MapScreenprops, MapScreenstate> {
constructor(props: MapScreenprops) {
super(props);
this.state = {
mapStylesURL: 'https://vector.dev.livingmap.com/styles/heathrow/styles.json',
zoomLevel: 13,
mapCenter: [-0.450897,51.4697442],
currentFloor: 6,
layerIDsAndFilters: new Map<string, string>(),
};
this.getStyleSheet();
}
mapInstance: MapboxGL.MapView | null;
render() {
return (
<View style={styles.container}>
<MapboxGL.MapView
style={styles.map}
logoEnabled={false}
styleURL={this.state.mapStylesURL}
attributionEnabled={false}>
<MapboxGL.Camera
zoomLevel={this.state.zoomLevel}
centerCoordinate={this.state.mapCenter}
/>
{this.generateSymbolLayers()}
</MapboxGL.MapView>
</View>
);
}
getSymbolLayersAndExistingFilters(styleSheetData: any) {
let layerObject = styleSheetData['layers'];
var layersAndFiltersMap = new Map<string, string>();
for (let layer of layerObject) {
if (layer['source'] == 'lm') {
let preexistingFilter = layer['filter'];
layersAndFiltersMap.set(layer['id'], preexistingFilter);
}
}
this.setState({layerIDsAndFilters: layersAndFiltersMap});
}
generateIndividualLayerFilters = (
layerID: string,
preExistingFilter: string,
) => {
return (
<MapboxGL.SymbolLayer
id={layerID}
key={layerID}
filter={[
'all',
preExistingFilter,
[
'any',
['==', ['get', 'floor_id'], this.state.currentFloor],
['==', ['get', 'floor_id'], ''],
['!', ['has', ['get', 'floor_id']]],
[
'all',
['==', ['get', 'floor_id'], '0.0'],
['==', ['get', 'indoor'], false],
],
],
]}></MapboxGL.SymbolLayer>
);
};
async getStyleSheet() {
(await fetch(LMConstants.MappingConstants.styleURL))
.json()
.then((result) => this.getSymbolLayersAndExistingFilters(result));
}
generateSymbolLayers = () => {
console.log('HERE')
let symbolLayers = [];
let layersArray = Array.from(this.state.layerIDsAndFilters.keys());
console.log('layersArray:', layersArray)
for (let layerID of layersArray) {
let layer = this.generateIndividualLayerFilters(
layerID,
this.state.layerIDsAndFilters.get(layerID),
);
symbolLayers.push(layer);
}
console.log(symbolLayers)
return symbolLayers;
};
}
const styles = StyleSheet.create({
container: {
height:
Dimensions.get('window').height - LMConstants.UIConstants.navBarHeight,
width: Dimensions.get('window').width,
},
map: {
flex: 1,
},
});
export default MapScreen;
Here is the output stack trace:
com.livingmap.surveyapp E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle
java.lang.ClassCastException: com.mapbox.mapboxsdk.style.layers.FillLayer cannot be cast to com.mapbox.mapboxsdk.style.layers.SymbolLayer
at com.mapbox.rctmgl.components.styles.layers.RCTMGLSymbolLayer.addStyles(RCTMGLSymbolLayer.java:45)
at com.mapbox.rctmgl.components.styles.layers.RCTLayer.addToMap(RCTLayer.java:260)
at com.mapbox.rctmgl.components.styles.layers.RCTMGLSymbolLayer.addToMap(RCTMGLSymbolLayer.java:29)
at com.mapbox.rctmgl.components.mapview.RCTMGLMapView.addQueuedFeatures(RCTMGLMapView.java:534)
at com.mapbox.rctmgl.components.mapview.RCTMGLMapView$1.onStyleLoaded(RCTMGLMapView.java:434)
at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:964)
at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:221)
at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1316)
at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:198)
at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1106)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:174)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2020-11-26 10:44:45.911 19946-19946/com.livingmap.surveyapp E/libc++abi: terminating with uncaught exception of type jni::PendingJavaException
2020-11-26 10:44:45.911 19946-19946/com.livingmap.surveyapp A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 19946 (ngmap.surveyapp), pid 19946 (ngmap.surveyapp)
The crashes with this error:
E/ReactNativeJS: 'Mapbox error', 'Exception in onDidFinishLoadingStyle', { level: 'error',
tag: 'Mbgl-MapChangeReceiver',
message: 'Exception in onDidFinishLoadingStyle' }
Expected behavior
Symbol layers are added and all filters are applied and response to dynamic changes in the state (this.state.currentFloor in this instance)
Versions (please complete the following information):
Screenshots
Image 1 - This is the error screen displayed by Android on instantionation of the MapScreen Component.
Images 2, 3 and 4 - Give an example of the expected behaviour as demonstrated by iOS for comparison. The images are sequential and show the changing of the floor. This can be emulated in the example code by changing the currentFloor value in the MapScreen state. Note that some of the functionality shown on the iOS screen has been omitted from the example code given here for the sake of brevity.
Image 1 - Android Result | Image 2 - iOS |Image 3 - iOS |Image 4 - iOS
-------------------------|-------------------------|-------------------------|-------------------------
|
|
| 
Additional context
This functionality has been successfully on iOS (iOS 14.2.1, iPhone 12 Pro, Simulator and Device). The implementation works well on iOS.
EDIT: Realign images (ferdicus)
Quick note on replicating the issue - the server that hosts the styles is has automated downtime from 1900 GMT to 0700 GMT. If you are attempting to replicate the issue in this scheduled downtime then let me know and I will ensure that the servers are serving.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This is still an issue
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I've just checked this issue and it is still a problem. Bumping this issue but since I seem to be the only person reporting the issue then I am going to jump into the source and have a look at it myself.
@NathanJozef, sorry to be such a buzz kill, but yeah - I don't think this will get any love in the near future.
Just keeping this repo clean (issue grooming/ deps updates/ PR checks) is enough for one person, even more so when that person only has one weekday for this repo.
@ferdicus, that's absolutely fine mate. Thank you for coming out and saying as much. At least it leaves us in little doubt of what is happening. I've forked the repo and will see if I can get a fix for it.
Appreciate all you've done with the repo so far so thank you for that.