具有符号层和圆形层崩溃的Android Studio Mapbox层问题

问题描述

我正在开发一个地理可视化数据图,该图将根据不同的数字值绘制不同颜色的图。并且,也希望数字值也可以显示在圆圈的顶部(这是围绕路线绕行的道路中的空气污染数据)。问题是当同时应用两层SymbolLayer和CircleLayer时,它们会使移动应用程序崩溃,这是行不通的。我试过仅测试它们工作的一层,只有当这两个层都应用时它们才崩溃。在有彩色圆圈且数字值标签也存在的情况下,两层拖曳是否都可能工作?另外,我正在使用存储在Tilesets中的数据。以下是该应用程序的图像链接。由于这是我第一次使用StackOverflow,因此无法发布图片

Click to view the Mobile App UI

This is my Tileset that I am using

        //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中的图层名称。您可以在SymbolLayerCircleLayer等的每个构造函数中定义任何唯一的“ layerId” ...

通过将相同的源ID放在SymbolLayerCircleLayer构造函数的第二个参数中,可以为每个层使用相同的数据源。请注意,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

enter image description here