Android Studio Mapbox 图层问题,符号图层和圆图层崩溃
Android Studio Mapbox Layer Problem with both Symbol Layer and Circle Layer Crash
我正在开发一个地理可视化数据地图,它会根据不同的数值绘制不同颜色的地图。并且,也希望在圆圈顶部可视化数值(它是围绕路线盘旋的道路中的空气污染数据)。问题是,当同时应用 SymbolLayer 和 CircleLayer 这两个图层时,它们会使移动应用程序崩溃,而这不起作用。我尝试只测试它们工作的一层,只有当它们都应用时它们才会崩溃。是否有可能在存在彩色圆圈且数值标签也存在的情况下,两层丝束都起作用?此外,我正在使用存储在 Tilesets 中的数据。下面是应用程序的图像 link。无法 post 图片,因为这是我第一次使用 Whosebug。
//Map View
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.LIGHT, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
style.addSource(new VectorSource(
VECTOR_SOURCE_ID,
"http://api.mapbox.com/v4/"+TILESET_KEY+".json?access_token=" + Mapbox.getAccessToken()
));
SymbolLayer label =new SymbolLayer(TILESET_LAYER_ID, VECTOR_SOURCE_ID);
label.setSourceLayer(VECTOR_SOURCE_ID);
label.withProperties(
textField(get("gaslvl_PM")), //This contains the number values
textSize(17f),
textColor(Color.RED),
textVariableAnchor(
new String[]{TEXT_ANCHOR_TOP, TEXT_ANCHOR_BOTTOM, TEXT_ANCHOR_LEFT, TEXT_ANCHOR_RIGHT}),
textJustify(TEXT_JUSTIFY_AUTO),
textRadialOffset(0.5f)
);
label.setFilter(all(
//This is to filter out the multiple rounds in the route of one full roundtrip.
//To prevent the same data from the same area to overlap.
eq(literal("roundtrip_number"), literal(roundT_val))));
style.addLayer(label);
CircleLayer circleLayer = new CircleLayer(TILESET_LAYER_ID, VECTOR_SOURCE_ID);
circleLayer.setSourceLayer(VECTOR_SOURCE_ID);
circleLayer.withProperties(
circleRadius(
interpolate(
exponential(1.75f),
zoom(),
stop(12, 2f),
stop(22, 180f)
)),
circleColor(
match(
get(TILESET_LAYER_ID),rgb(0, 0, 0),
stop("0", COLOR_GREEN),
stop("1", COLOR_GREEN),
stop("2", COLOR_GREEN),
stop("3", COLOR_GREEN),
stop("4", COLOR_GREEN)
//Didn't add the rest of the "stop colors" since it's 500 lines.
));
circleLayer.setFilter(all(
eq(literal("roundtrip_number"), literal(roundT_val))
//eq(literal("date"), literal(Date.valueOf(date_val)))
));
style.addLayer(circleLayer);
}
});
}
});
附加代码有几个问题,我没有 100% 的信心,但我认为崩溃的发生是因为您为符号图层和圆形图层分配了相同的图层 ID。
您是否看到类似于下面的故障转储?它说“层 layer-id 已经存在”。
2020-11-06 22:54:49.324 7267-7267/com.example.sof95859
E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle
com.mapbox.mapboxsdk.style.layers.CannotAddLayerException: Layer layer-id already exists
at com.mapbox.mapboxsdk.maps.NativeMapView.nativeAddLayer(Native Method)
at com.mapbox.mapboxsdk.maps.NativeMapView.addLayer(NativeMapView.java:858)
at com.mapbox.mapboxsdk.maps.Style.addLayer(Style.java:191)
at com.example.sof95859.MainActivity.onStyleLoaded(MainActivity.java:121)
at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:963)
at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:225)
at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1373)
at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:198)
at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1166)
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)
我还附上了访问我的示例层的工作示例。
public class MainActivity extends AppCompatActivity {
private static final String TILESET_KEY = "yochi.6v4pssqn";
private static final String VECTOR_SOURCE_ID = "vector-source";
private static final String VECTOR_SOURCE_LAYER_ID = "sof95859-0wzvvn";
private static final String TILESET_SYMBOL_LAYER_ID = "symbol-layer-id";
private static final String TILESET_CIRCLE_LAYER_ID = "circle-layer-id";
private static final int roundT_val = 2;
private static final Expression COLOR_GREEN = rgb(0, 255, 0);
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
CameraUpdate update = CameraUpdateFactory.newLatLngBounds(
LatLngBounds.from(1, 1, -1, -1), 0, 0, 0 );
mapboxMap.easeCamera(update);
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// tileset.json API call did not work for me
style.addSource(new VectorSource(VECTOR_SOURCE_ID, "mapbox://" + TILESET_KEY));
// Asssign unique layer ID
SymbolLayer label =new SymbolLayer(TILESET_SYMBOL_LAYER_ID, VECTOR_SOURCE_ID);
// Set layer name by checking Tileset in Studio
label.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
label.withProperties(
textField(get("gaslvl_PM")), //This contains the number values
textSize(17f),
textColor(Color.RED),
textVariableAnchor(
new String[]{TEXT_ANCHOR_TOP, TEXT_ANCHOR_BOTTOM, TEXT_ANCHOR_LEFT, TEXT_ANCHOR_RIGHT}),
textJustify(TEXT_JUSTIFY_AUTO),
textRadialOffset(0.5f)
);
label.setFilter(all(
//This is to filter out the multiple rounds in the route of one full roundtrip.
//To prevent the same data from the same area to overlap.
eq(literal("roundtrip_number"), literal(roundT_val))));
style.addLayer(label);
CircleLayer circleLayer = new CircleLayer(TILESET_CIRCLE_LAYER_ID, VECTOR_SOURCE_ID);
// Set layer name by checking Tileset in Studio
circleLayer.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
circleLayer.withProperties(
circleRadius(
interpolate(
exponential(1.75f),
zoom(),
stop(12, 2f),
stop(22, 180f)
)),
circleColor(
match(
// I think this is wrong
get(TILESET_CIRCLE_LAYER_ID),rgb(0, 0, 0),
stop("0", COLOR_GREEN),
stop("1", COLOR_GREEN),
stop("2", COLOR_GREEN),
stop("3", COLOR_GREEN),
stop("4", COLOR_GREEN)
// the number of parentheses is wrong
)));
circleLayer.setFilter(all(
eq(literal("roundtrip_number"), literal(roundT_val))
//eq(literal("date"), literal(Date.valueOf(date_val)))
));
style.addLayer(circleLayer);
}
});
}
});
}
已添加评论
重要的是 SymbolLayer
的“layerId”参数,CircleLayer
构造函数不是 tileset 中的图层名称。您在 SymbolLayer
、CircleLayer
等的每个构造函数中定义任何唯一的“layerId”...
通过在 SymbolLayer
、CircleLayer
构造函数的第二个参数中放置相同的源 ID,您可以为每一层使用相同的数据源。请注意,Source ID 也是您在 style.addSource.
中定义的任何 Source ID
然后到select每一层应该用哪个Layer,你调用label.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
这是 ID 的摘要
- TILESET_KEY: Studio 提供的 Tileset ID
- VECTOR_SOURCE_LAYER_ID: Studio 提供的图层名称
- VECTOR_SOURCE_ID:您可以定义的任何来源 ID
- TILESET_SYMBOL_LAYER_ID,TILESET_CIRCLE_LAYER_ID: 任何你可以定义的图层ID
我正在开发一个地理可视化数据地图,它会根据不同的数值绘制不同颜色的地图。并且,也希望在圆圈顶部可视化数值(它是围绕路线盘旋的道路中的空气污染数据)。问题是,当同时应用 SymbolLayer 和 CircleLayer 这两个图层时,它们会使移动应用程序崩溃,而这不起作用。我尝试只测试它们工作的一层,只有当它们都应用时它们才会崩溃。是否有可能在存在彩色圆圈且数值标签也存在的情况下,两层丝束都起作用?此外,我正在使用存储在 Tilesets 中的数据。下面是应用程序的图像 link。无法 post 图片,因为这是我第一次使用 Whosebug。
//Map View
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.LIGHT, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
style.addSource(new VectorSource(
VECTOR_SOURCE_ID,
"http://api.mapbox.com/v4/"+TILESET_KEY+".json?access_token=" + Mapbox.getAccessToken()
));
SymbolLayer label =new SymbolLayer(TILESET_LAYER_ID, VECTOR_SOURCE_ID);
label.setSourceLayer(VECTOR_SOURCE_ID);
label.withProperties(
textField(get("gaslvl_PM")), //This contains the number values
textSize(17f),
textColor(Color.RED),
textVariableAnchor(
new String[]{TEXT_ANCHOR_TOP, TEXT_ANCHOR_BOTTOM, TEXT_ANCHOR_LEFT, TEXT_ANCHOR_RIGHT}),
textJustify(TEXT_JUSTIFY_AUTO),
textRadialOffset(0.5f)
);
label.setFilter(all(
//This is to filter out the multiple rounds in the route of one full roundtrip.
//To prevent the same data from the same area to overlap.
eq(literal("roundtrip_number"), literal(roundT_val))));
style.addLayer(label);
CircleLayer circleLayer = new CircleLayer(TILESET_LAYER_ID, VECTOR_SOURCE_ID);
circleLayer.setSourceLayer(VECTOR_SOURCE_ID);
circleLayer.withProperties(
circleRadius(
interpolate(
exponential(1.75f),
zoom(),
stop(12, 2f),
stop(22, 180f)
)),
circleColor(
match(
get(TILESET_LAYER_ID),rgb(0, 0, 0),
stop("0", COLOR_GREEN),
stop("1", COLOR_GREEN),
stop("2", COLOR_GREEN),
stop("3", COLOR_GREEN),
stop("4", COLOR_GREEN)
//Didn't add the rest of the "stop colors" since it's 500 lines.
));
circleLayer.setFilter(all(
eq(literal("roundtrip_number"), literal(roundT_val))
//eq(literal("date"), literal(Date.valueOf(date_val)))
));
style.addLayer(circleLayer);
}
});
}
});
附加代码有几个问题,我没有 100% 的信心,但我认为崩溃的发生是因为您为符号图层和圆形图层分配了相同的图层 ID。
您是否看到类似于下面的故障转储?它说“层 layer-id 已经存在”。
2020-11-06 22:54:49.324 7267-7267/com.example.sof95859 E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle com.mapbox.mapboxsdk.style.layers.CannotAddLayerException: Layer layer-id already exists at com.mapbox.mapboxsdk.maps.NativeMapView.nativeAddLayer(Native Method) at com.mapbox.mapboxsdk.maps.NativeMapView.addLayer(NativeMapView.java:858) at com.mapbox.mapboxsdk.maps.Style.addLayer(Style.java:191) at com.example.sof95859.MainActivity.onStyleLoaded(MainActivity.java:121) at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:963) at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:225) at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1373) at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:198) at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1166) 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)
我还附上了访问我的示例层的工作示例。
public class MainActivity extends AppCompatActivity {
private static final String TILESET_KEY = "yochi.6v4pssqn";
private static final String VECTOR_SOURCE_ID = "vector-source";
private static final String VECTOR_SOURCE_LAYER_ID = "sof95859-0wzvvn";
private static final String TILESET_SYMBOL_LAYER_ID = "symbol-layer-id";
private static final String TILESET_CIRCLE_LAYER_ID = "circle-layer-id";
private static final int roundT_val = 2;
private static final Expression COLOR_GREEN = rgb(0, 255, 0);
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
CameraUpdate update = CameraUpdateFactory.newLatLngBounds(
LatLngBounds.from(1, 1, -1, -1), 0, 0, 0 );
mapboxMap.easeCamera(update);
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// tileset.json API call did not work for me
style.addSource(new VectorSource(VECTOR_SOURCE_ID, "mapbox://" + TILESET_KEY));
// Asssign unique layer ID
SymbolLayer label =new SymbolLayer(TILESET_SYMBOL_LAYER_ID, VECTOR_SOURCE_ID);
// Set layer name by checking Tileset in Studio
label.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
label.withProperties(
textField(get("gaslvl_PM")), //This contains the number values
textSize(17f),
textColor(Color.RED),
textVariableAnchor(
new String[]{TEXT_ANCHOR_TOP, TEXT_ANCHOR_BOTTOM, TEXT_ANCHOR_LEFT, TEXT_ANCHOR_RIGHT}),
textJustify(TEXT_JUSTIFY_AUTO),
textRadialOffset(0.5f)
);
label.setFilter(all(
//This is to filter out the multiple rounds in the route of one full roundtrip.
//To prevent the same data from the same area to overlap.
eq(literal("roundtrip_number"), literal(roundT_val))));
style.addLayer(label);
CircleLayer circleLayer = new CircleLayer(TILESET_CIRCLE_LAYER_ID, VECTOR_SOURCE_ID);
// Set layer name by checking Tileset in Studio
circleLayer.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
circleLayer.withProperties(
circleRadius(
interpolate(
exponential(1.75f),
zoom(),
stop(12, 2f),
stop(22, 180f)
)),
circleColor(
match(
// I think this is wrong
get(TILESET_CIRCLE_LAYER_ID),rgb(0, 0, 0),
stop("0", COLOR_GREEN),
stop("1", COLOR_GREEN),
stop("2", COLOR_GREEN),
stop("3", COLOR_GREEN),
stop("4", COLOR_GREEN)
// the number of parentheses is wrong
)));
circleLayer.setFilter(all(
eq(literal("roundtrip_number"), literal(roundT_val))
//eq(literal("date"), literal(Date.valueOf(date_val)))
));
style.addLayer(circleLayer);
}
});
}
});
}
已添加评论
重要的是 SymbolLayer
的“layerId”参数,CircleLayer
构造函数不是 tileset 中的图层名称。您在 SymbolLayer
、CircleLayer
等的每个构造函数中定义任何唯一的“layerId”...
通过在 SymbolLayer
、CircleLayer
构造函数的第二个参数中放置相同的源 ID,您可以为每一层使用相同的数据源。请注意,Source ID 也是您在 style.addSource.
Source ID
然后到select每一层应该用哪个Layer,你调用label.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
这是 ID 的摘要
- TILESET_KEY: Studio 提供的 Tileset ID
- VECTOR_SOURCE_LAYER_ID: Studio 提供的图层名称
- VECTOR_SOURCE_ID:您可以定义的任何来源 ID
- TILESET_SYMBOL_LAYER_ID,TILESET_CIRCLE_LAYER_ID: 任何你可以定义的图层ID