【问题标题】:Android Studio Mapbox Layer Problem with both Symbol Layer and Circle Layer Crash符号层和圆形层崩溃的Android Studio Mapbox层问题
【发布时间】:2021-02-18 20:05:12
【问题描述】:

我正在开发一个地理可视化数据地图,它将根据不同的数值绘制不同颜色的地图。并且,还希望在圆圈顶部可视化数值(它是围绕路线盘旋的道路中的空气污染数据)。问题是当两个图层 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, 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);

                }
            });
        }
    });

【问题讨论】:

    标签: android mapbox mapbox-android


    【解决方案1】:

    附加的代码有几个问题,我没有 100% 的信心,但我认为发生崩溃是因为您为符号层和圆形层分配了相同的层 ID。

    您是否看到类似于下面的故障转储?它说“图层 layer-id 已经存在”。

    2020-11-06 22:54:49.324 7267-7267/com.example.sof95859 E/Mbgl-MapChangeReceiver:onDidFinishLoadingStyle 中的异常 com.mapbox.mapboxsdk.style.layers.CannotAddLayerException:图层图层 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) 在 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, 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);
    
                        }
                    });
                }
            });
        }
    

    添加了cmets

    重要的是SymbolLayer的“layerId”参数,CircleLayer构造函数不是tileset中的图层名称。您在SymbolLayerCircleLayer 等的每个构造函数中定义任何唯一的“layerId”...

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

    【讨论】:

    • 我明白了。是的,我确实为两个图层分配了相同的图层 ID。目的是两个图层将获得相同的值,因为 CircleLayer 将根据图层 ID (gas_lvlPM) 的值对点进行着色,并且 SymbolLayer 还将图层 ID (gas_lvlPM) 值添加为彩色点上方的标签(CircleLayer提供)。有什么方法可以让两个彩色点的值都显示在地图中,并且两者都在相同的图层 ID 上获取数据?
    • 另外,我的数据是一个 Excel 文件,其中仅包含这些属性日期、gaslvl_CO、gaslvl_OZ、gaslvl_PM、lat、lon、roundtrip_number 和时间。而且,在 Tilesets 中上传后,它只有 1 层。我很抱歉,因为我对使用 Mapbox 很陌生。
    • 另外,能否提供您使用的 Tileset Studion 的屏幕截图页面,以便我更准确地识别 VECTOR_SOURCE_LAYER_ID、TILESET_CIRCLE_LAYER_ID 和 TILESET_SYMBOL_LAYER_ID?
    • 另外,我添加了我在上面使用的瓦片集的图像。
    • 在我的回答中添加了 cmets
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多