问题描述
我正在开发一个地理可视化数据图,该图将根据不同的数字值绘制不同颜色的图。并且,也希望数字值也可以显示在圆圈的顶部(这是围绕路线绕行的道路中的空气污染数据)。问题是当同时应用两层SymbolLayer和CircleLayer时,它们会使移动应用程序崩溃,这是行不通的。我试过仅测试它们工作的一层,只有当这两个层都应用时它们才崩溃。在有彩色圆圈且数字值标签也存在的情况下,两层拖曳是否都可能工作?另外,我正在使用存储在Tilesets中的数据。以下是该应用程序的图像链接。由于这是我第一次使用StackOverflow,因此无法发布图片。
//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),stop("0",COLOR_GREEN),stop("1",stop("2",stop("3",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 layer-id已经存在”。
2020-11-06 22:54:49.324 7267-7267 / com.example.sof95859 E / Mbgl-MapChangeReceiver:onDidFinishLoadingStyle中的异常 com.mapbox.mapboxsdk.style.layers.CannotAddLayerException:图层layer-id已存在 com.mapbox.mapboxsdk.maps.NativeMapView.nativeAddLayer处(本机方法) 在com.mapbox.mapboxsdk.maps.NativeMapView.addLayer(NativeMapView.java:858) 在com.mapbox.mapboxsdk.maps.Style.addLayer(Style.java:191) at com.example.sof95859.MainActivity $ 1 $ 1.onStyleLoaded(MainActivity.java:121) 在com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:963) 在com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:225) 在com.mapbox.mapboxsdk.maps.MapView $ MapCallback.onDidFinishLoadingStyle(MapView.java:1373) 在com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:198) 在com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1166) 在android.os.MessageQueue.nativePollOnce(本机方法) 在android.os.MessageQueue.next(MessageQueue.java:336) 在android.os.Looper.loop(Looper.java:174) 在android.app.ActivityThread.main(ActivityThread.java:7356) 在java.lang.reflect.Method.invoke(本机方法) 在com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:492) 在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 );
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),stop("0",COLOR_GREEN),stop("1",stop("2",stop("3",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” ...
通过将相同的源ID放在SymbolLayer
,CircleLayer
构造函数的第二个参数中,可以为每个层使用相同的数据源。请注意,Source ID也是您在style.addSource中定义的任何Source ID
。
然后选择要在每个图层中使用哪个图层,请调用label.setSourceLayer(VECTOR_SOURCE_LAYER_ID);
这是ID的摘要
- TILESET_KEY:Studio提供的图块集ID
- VECTOR_SOURCE_LAYER_ID:Studio提供的图层名称
- VECTOR_SOURCE_ID:您可以定义的任何源ID
- TILESET_SYMBOL_LAYER_ID,TILESET_CIRCLE_LAYER_ID:您可以定义的任何层ID