4

我正在开发一个包含 Webview 的 Android 应用程序。webview对应的HTML主要包含JavaScript代码;它从地理服务器检索建筑物的地图。我使用 Leaflet 来显示不同的图层。每个基础层是一个地板。

我正在向 Android 的基础层添加 2 个叠加层;一个是热图,另一个是一组表示某些传感器位置的标记。由于 Android 中的 JavaScript 接口,JavaScript 代码可以获取从 Android 创建的数据集。

当我只显示一个叠加层时它可以工作。一旦我想显示两个覆盖,或者在我显示一个覆盖后,隐藏它并显示另一个,应用程序就会崩溃。根据首先添加的叠加层,我有不同的错误。

真的很奇怪:它只发生在我的平板电脑(非常便宜)上,而不是 AVD。

这是我的 JavaScript 代码:

<script type="text/javascript" charset="utf-8">
        var map, baseLayers, heatmapLayer, sensorsLayer;


        var ground_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
                                           {
                                           layers: 'ground_floor',
                                           format: 'image/png'
                                           });

        var first_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
                                          {
                                          layers: 'first_floor',
                                          format: 'image/png'
                                          });

        var second_floor = new L.tileLayer.wms('http://192.168.1.16/geoserver/wms',
                                           {
                                           layers: 'second_floor',
                                           format: 'image/png'
                                           });

        var current_floor = ground_floor;

        baseLayers = {
            "Ground floor": ground_floor,
            "First floor": first_floor,
            "Second floor": second_floor
        };            

        map = new L.Map('map', {
                        center: new L.LatLng(-45, 170),
                        zoom: 30,
                        layers: [ground_floor],
                        crs: L.CRS.EPSG900913
                        }).setView([-45.8668664, 170.5185323], 31);

        var control = L.control.layers(baseLayers).addTo(map);

        map.on('baselayerchange', onBaseLayerChanged);

        // Called when the base layer (meaning the floor) is changed
        function onBaseLayerChanged(event) {
            // Update the current floor
            if (event.layer == ground_floor)
                current_floor = ground_floor;
            else if (event.layer == first_floor)
                current_floor = first_floor;
            else if (event.layer == second_floor)
                current_floor = second_floor;
            else
                Android.debug("Wrong base layer");

            Android.debug("yo1");

            // Update the heatmap and sensors' location
            // if they are displayed
            if (map.hasLayer(heatmapLayer)) {
                removeHeatmap();
                addHeatmap();
            }

            Android.debug("yo2");

            if (map.hasLayer(sensorsLayer)) {
                Android.debug("yo3");
                removeSensors();
                addSensors();
                Android.debug("yo4");
            }

        }

        function addHeatmap() {
            heatmapLayer = L.TileLayer.heatMap({
                                               // radius could be absolute or relative
                                               // absolute: radius in meters, relative: radius in pixels
                                               radius: { value: 5, absolute: true },
                                               opacity: 0.8,
                                               gradient: {
                                               0.45: "rgb(0,0,255)",
                                               0.55: "rgb(0,255,255)",
                                               0.65: "rgb(0,255,0)",
                                               0.95: "yellow",
                                               1.0: "rgb(255,0,0)"
                                               }
                                               });

            var dataSet;

            if (current_floor == ground_floor)
                dataSet = JSON.parse(Android.getDataSetGroundFloor());
            else if (current_floor == first_floor)
                dataSet = JSON.parse(Android.getDataSetFirstFloor());
            else if (current_floor == second_floor)
                dataSet = JSON.parse(Android.getDataSetSecondFloor());
            else
                Android.debug("Error getDataSet : wrong floor");

            heatmapLayer.setData(dataSet.data);

            control.addOverlay(heatmapLayer, "Heatmap");
            heatmapLayer.addTo(map);
        }

        function removeHeatmap() {
            control.removeLayer(heatmapLayer);
            map.removeLayer(heatmapLayer);
        }

        function addSensors() {
            var sLat, sLon;
            var markers = new Array();

            if (current_floor == ground_floor) {
                sLat = JSON.parse(Android.getLatitudesGroundFloor());
                sLon = JSON.parse(Android.getLongitudesGroundFloor());
            }
            else if (current_floor == first_floor) {
                sLat = JSON.parse(Android.getLatitudesFirstFloor());
                sLon = JSON.parse(Android.getLongitudesFirstFloor());
            }
            else if (current_floor == second_floor) {
                sLat = JSON.parse(Android.getLatitudesSecondFloor());
                sLon = JSON.parse(Android.getLongitudesSecondFloor());
            }
            else
                Android.debug("Error getCoordinates : wrong floor");

            for (i=0; i<sLat.length && i<sLon.length; i++) {
                var marker = L.marker([sLat[i],sLon[i]]);
                markers.push(marker);
            }

            sensorsLayer = L.layerGroup(markers);

            control.addOverlay(sensorsLayer, "Sensors");
            sensorsLayer.addTo(map);
        }

        function removeSensors() {
            control.removeLayer(sensorsLayer);
            map.removeLayer(sensorsLayer);
        }

    </script>

如果我先添加热图,然后在传感器上添加以下代码的“sensorsLatFloor”上的 NullPointerException:

public JSONArray getLatitudesGroundFloor() {
        if (!isSensorsQueryDone())
            new SelectSensorsLocationATask(SensorsFragment.this).execute();

        // Wait for the end of the query
        while (!querySuccessful) {}

        JSONArray latJSON = null;
        latJSON = new JSONArray(sensorsLatGroundFloor);

        return latJSON;
    }

这是针对一楼的,但对每一层都是一样的。“sensorsLatGroundFloor”是在本地数据库中查询后由 AsyncTask SelectSensorsLocationATask 填充的 ArrayList。该代码有效,因为它在我只想显示传感器时有效。

当我先显示传感器,然后显示热图时,应用程序崩溃并且 LogCat 中出现以下错误:

JNI ERROR (app bug): accessed staled weak global reference 0xffffffff (index 65535 in a table of size 8)
VM aborting
Fatal signal 11 (SIGSEV) at 0xdeadd00d

这很奇怪,因为我根本不操作 JNI 代码......

此外,我还有另一个错误,这一定很愚蠢,但我不明白为什么它不起作用。看看我的 JavaScript 代码的这一部分:

// Called when the base layer (meaning the floor) is changed
        function onBaseLayerChanged(event) {
            // Update the current floor
            if (event.layer == ground_floor)
                current_floor = ground_floor;
            else if (event.layer == first_floor)
                current_floor = first_floor;
            else if (event.layer == second_floor)
                current_floor = second_floor;
            else
                Android.debug("Wrong base layer");

            Android.debug("yo1");

            // Update the heatmap and sensors' location
            // if they are displayed
            if (map.hasLayer(heatmapLayer)) {
                removeHeatmap();
                addHeatmap();
            }

            Android.debug("yo2");

            if (map.hasLayer(sensorsLayer)) {
                Android.debug("yo3");
                removeSensors();
                addSensors();
                Android.debug("yo4");
            }

        }

当我切换基础层(即地板)时,此功能应该更新显示的叠加层。它适用于热图,但不适用于传感器......如果热图不在地图上,则该功能已完成,它甚至不看我的第二个 if。您可以看到我的“Android.debug”,它在 LogCat 中显示我作为参数输入的消息。在这里,LogCat 只显示“yo1”。

编辑:我想出了最后一个错误。问题似乎是传单功能“hasLayer”。如果地图指示了图层,则返回 true。所以在我看来,如果不是,它应该返回 false ......这是有道理的。但不是它,而是使代码错误,因此函数之后的代码被忽略。要么我犯了一个我调用它时看不到的错误,要么Leaflet做了一个无用的功能......所以我一定犯了一个愚蠢的错误,但我没有找到它!

我希望我已经足够清楚,可以让您理解我的问题...如果您需要更多 Android 代码,请告诉我,尽管我认为这不会有帮助。

提前谢谢你。

*问题已修复*

错误是由 Android 代码中的任务同步问题引起的。您可以看到我使用变量“querySuccessful”等待查询结束。实际上,我只是从 AsyncTask 操作这个变量:我在开始时将其设置为 false,最后将其设置为 true。现在我在启动 AsyncTask 之前将其设置为 true,并且应用程序正常工作,我没有更多错误。

Leaflet 函数 hasLayer 仍然存在一些问题;当我切换基础层一次(有时两次)时它可以工作,但随后它停止工作。但显然这可能是 Leaflet 的错误,将在下一个版本中修复。

4

0 回答 0