Android动态加载标记最佳策略

问题描述 投票:0回答:3

我有一个带有谷歌地图的Android地图,它可以根据用户屏幕位置从服务器动态加载标记。因此,例如,如果用户移动地图,我只需向服务器发出请求,然后发送屏幕边界,并基于此获得标记数据(id 和坐标),稍后将其解析并创建为实际指针。问题是,当用户返回到同一区域(之前创建了哪些标记)时,我仍然发出相同的请求并获取相同的数据(但显然我不会让重新创建该标记,所以我只是运行 for 循环遍历那里的所有标记)在地图上,检查地图标记 id 是否相等,服务器发送数据标记 id,如果相等,我只需中断循环)

try {
                Collection<MarkerItemData> mapMarkers = algorithm.getItems();
                JSONObject jsonObject = new JSONObject(strings[0]);
                JSONArray respondArray = jsonObject.getJSONArray("respond");
                list = new ArrayList();
                for (int i = 0; i < respondArray.length(); i++) {
                    JSONObject station = respondArray.getJSONObject(i);
                    int id = station.getInt("_id");
                    boolean skip = false;
                    for (final MarkerItemData m : mapMarkers) {
                        if (m.getId() == id) {
                            skip = true;
                            break;
                        }
                    }
                }
            }

但是我不认为这种方法是最好的。我还有其他应该可行的想法(至少我认为)

  • 发送到服务器屏幕边界以及屏幕上可见的所有标记 ID(我可以选择屏幕范围内的所有标记以及哪些 ID 不在屏幕边界内)
  • 每次从Android应用程序中删除标记,并基本上每次从服务器重新创建所有标记(我个人认为这是一个糟糕的解决方案)

那么这些想法中哪一个是最好的呢?还有其他想法吗? (对不起我的英语)

android google-maps dynamic
3个回答
2
投票

将屏幕边界发送到服务器和屏幕上当前可见标记的 id-s 是您最好的选择。但仍然存在一些麻烦的问题。如何找到屏幕边界指定范围内包含的所有标记?如果新标记到达您的服务器或某些标记被删除怎么办?在这种情况下,你能提供一个可维护的结构吗?还是你会一一测试数据库中与标记相对应的每个点,看看它是否位于范围内?考虑到所有这些,您需要找到一种方法来优化存储和查询点,即点标记的纬度和经度对。您应该使用一种常见的空间索引方法来执行空间索引。

空间索引的方法有很多,根据用例,一种方法可能比另一种方法稍好。长话短说,由于您需要在这种情况下查询范围,因此您应该实现四叉树。四叉树被称为树形数据结构,其中每个内部节点恰好有四个子节点(西北、东北、西南、东南)。如果你对这个结构没有了解,我相信你一个小时就能明白它的基础知识,但从头开始详细解释会导致我损失太多时间。因此,我跳过有关四叉树的实现细节。有几个来源已经比我更好地解释了这种结构,并且您可以轻松找到开源库。

我只会为你的四叉树提供伪Java方法来查找出现在屏幕边界范围内的所有点,不包括上一个屏幕中已经存在的点:

ArrayList<LatLng> queryRange(QuadLevel level, float[] screenBounds, ArrayList<LatLng> prevPoints) { 

    // Initialize a list to hold the found points
    ArrayList<LatLng> pointsInRange = new ArrayList<>();

    if (!quadtreeBounds.intersects(screenBounds))
        return pointsInRange;

    // Find the points that are in the current quad level
    for (LatLng point : level.getPoints()) {
        // If the current point is in screen bounds and it is not contained by prevPoints
        if (point.isInRange(screenBounds) 
            && !prevPoints.contains(point))
            pointsInRange.add(point);
    }

    // If there are no children, return
    if (level.hasNoChildren())
        return pointsInRange;

    // Else, continue to look up children
    pointsInRange.addAll(queryRange(level.northwest, screenBounds, prevPoints));
    pointsInRange.addAll(queryRange(level.northeast, screenBounds, prevPoints));
    pointsInRange.addAll(queryRange(level.southwest, screenBounds, prevPoints));
    pointsInRange.addAll(queryRange(level.southeast, screenBounds, prevPoints));

    return pointsInRange;
}

1
投票

扩展

HashSet<MarkerOptions>
,以便在添加
MarkerOptions
时将其添加到地图中。

class MarkerSet extends HashSet<MarkerOptions> {
    @Override
    public boolean add(MarkerOptions markerOptions) {

        boolean didAdd = super.add(markerOptions);

        if(didAdd) {
            mMap.addMarker(markerOptions);
        }
        return didAdd;
    }
}

在地图活动中维护一个 LatLngBounds 对象。此 LatLngBounds 对象将存储您已从服务器请求数据的边界。

当地图的相机移动时,检查新边界是否在当前存储的边界内,如果不请求服务器,则增加边界,否则不请求服务器。

mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
    @Override
    public void onCameraMove() {

        LatLngBounds currentBounds = mMap.getProjection().getVisibleRegion().latLngBounds;

        if (mBounds == null) {
            mBounds = currentBounds;
            // Perform server request and get markers passing in currentBounds
            // Following to be performed in server request's callback
            MarkerOptions markerOptions = new MarkerOptions();
            // set marker options here
            mMarkerSet.add(markerOptions);

        } else {

            if (!(mBounds.contains(currentBounds.northeast) || mBounds.contains(currentBounds.southwest))) {
                mBounds = mBounds.including(currentBounds.northeast);
                mBounds = mBounds.including(currentBounds.southwest);

                // Perform server request and get markers passing in currentBounds
                // Following to be performed in server request's callback
                MarkerOptions markerOptions = new MarkerOptions();
                // set marker options here
                mMarkerSet.add(markerOptions);
            }

        }
    }
});

确保您始终调用服务器请求

currentBounds
。如果当
currentBounds
currentBounds
重叠时设法缩短
mBounds
,则可以改进该算法。

假设

请注意,这里的假设是当相机移动时,

currentBounds
会稍微从
mBounds
中掉出来。否则,不会加载新标记。 参考图像,如果用户从可见的绿色区域移动到橙色,则
mBounds
值将是蓝色矩形,因此白色区域不会被覆盖。然而,在实践中,完美地水平或垂直移动相机并不容易,这将导致调用服务器方法并加载未冒险区域的新标记。

希望这有帮助。 :)


1
投票

将屏幕上的所有可见标记存储在列表或本地数据库或某个位置中,如果不存在来自服务器的请求,则迭代列表中的现有标记。

© www.soinside.com 2019 - 2024. All rights reserved.