【问题标题】:Google Maps reuse marker but doesn't say it clearly?谷歌地图重复使用标记但没有说清楚?
【发布时间】:2014-04-04 15:30:38
【问题描述】:

我已经清理了我的代码以尽可能减少行数,但显示了我遇到的问题。

我的地图显示一些标记取决于相机位置。标记由 addMarker 添加到地图上,并存储在 HashMap 中,其中 Long 用于获取标记和数据库记录之间的引用。

地图上的每个标记都包含一个标题和一个 sn-p,它允许我显示 InfoWindow。在地图上我有一个 onInfoWindowClickListener(Marker mark);允许我显示一个对话框,其中包含比 infoWindow 所能做的更多的信息给用户。 监听器的params中的Marker标记与HashMap一起使用来检索数据库记录的id,将其传递给对话框以检索对话框中的信息。

当用户在屏幕上移动时,标记可能会被破坏,方法是检测它在移动后是一直在屏幕上还是在屏幕外。如果不是,我从 HashMap 中删除标记并使用 Marker.remove();方法将其从地图中删除。

如果幸运的话,所有这些都可以很好地工作。为什么?因为我发现 Maps 似乎重用了已删除的标记(为什么不),但 addMarker 方法和传递给 onInfoWindowClickListener 的标记在某些情况下并不相同。比较参考不起作用,等于也不起作用。所以我无法使用这两种方法来比较 HashMap 和 parmas 中的标记。手动比较似乎是唯一的解决方案,但在此之前,我更愿意询问您是否知道发生了什么。

我在下面的代码中是否有错误,或者是 Maps API 的错误,它返回了新标记但使用了旧标记?真的是一个旧标记还是api中线程之间的同步问题?这样做是不是一个坏主意,有更好的解决方案吗?

我不知道,也许你有什么想法?

public class MainActivity extends FragmentActivity{

    private enum CORNER {
            TOP_LEFT,
            TOP_RIGHT,
            BOT_LEFT,
            BOT_RIGHT
    };

    private GoogleMap map;
    private SupportMapFragment mapFrag;
    private Map<Long,Marker> markerMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            setContentView(R.layout.main_activity);
            markerMap = new HashMap<Long, Marker>();    
            mapFrag = (SupportMapFragment)getSupportFragmentManager().findFragme   ntById(R.id.maps_mv_map);
            map = mapFrag.getMap();

            map.setOnCameraChangeListener(new OnCameraChangeListener() {

                    @Override
                    public void onCameraChange(CameraPosition position) {
                            addSiteOnMap();//update displayed marker
                    }
            });

            map.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {

                    @Override
                    public void onInfoWindowClick(Marker arg0) {
                            InformationDialog dialog = new InformationDialog();
                            Bundle args = new Bundle();
                            System.out.println(arg0);//show reference to the marker to find the problem
                            //retrieve the db Id depends on marker
                            for(Long key : markerMap.keySet())
                            {
                                    if(markerMap.get(key).equals(arg0))
                                    {
                                            args.putLong("dbId",key);
                                            break;
                                    }
                            }
                            dialog.setArguments(args);
                            dialog.show(getSupportFragmentManager(), "information dialog");
                    }
            });
    }

    //get the LatLng for a corner
    private LatLng getCorner(CORNER corner)
    {
            int height = 0;
            int width = 0;
            if(corner == CORNER.BOT_LEFT || corner == CORNER.BOT_RIGHT)
                    height = mapFrag.getView().getHeight();
            if(corner == CORNER.BOT_RIGHT || corner == CORNER.TOP_RIGHT)
                    width = mapFrag.getView().getWidth();

            com.google.android.gms.maps.Projection pr = map.getProjection();
            return pr.fromScreenLocation(new Point(width,height));
    }

    private void addSitesOnMap()
    {
            List<Data> list = Database.getInstance(this).getData(getCorner(CORNER.TOP_RIGHT),getCorner(CORNER.BOT_LEFT));
            Set<Long> keys = markerMap.keySet();
            List<Long> idList = new ArrayList<Long>();
            for(Data site : list)
            {
                    idList.add(site.getDbId());
            }
            keys.retainAll(idList);
            Set<Long> oldKeys = markerMap.keySet();
            for(Long id : oldKeys)
            {
                    if(!keys.contains(id))
                    {
                            Marker marker = markerMap.remove(id);
                            marker.remove();
                    }
            }

            for(Data site : list)                          
            {
                    if(!markerMap.containsKey(site.getDbId()))//if the marker is not already display on the map
                    {
                            MarkerOptions options = new MarkerOptions();
                            options.position(site.getLoc());
                            options.title(site.getCityName());
                            DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, Locale.getDefault());
                            options.snippet(df.format(site.getDate().getTime()));

                            Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.marker);
                            options.icon(BitmapDescriptorFactory.fromBitmap(bp));
                            markerMap.put(Long.valueOf(site.getDbId()),map.addMarker(options));
                    }
            }
            for(Long key : markerMap.keySet())
            {
                    System.out.println(markerMap.get(key).getTitle()+" "+key+" "+markerLi  st.get(key));//show reference to the all marker in the map and information to help me find what reference is interesting for me
            }
    }
}   

感谢您的帮助

【问题讨论】:

    标签: android google-maps google-maps-markers


    【解决方案1】:

    根据 Java 文档:keySet() “返回此映射中包含的键的集合视图。集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。” (source)

    问题出在以下代码中:

            List<Data> list = Database.getInstance(this).getData(getCorner(CORNER.TOP_RIGHT),getCorner(CORNER.BOT_LEFT));
            Set<Long> keys = markerMap.keySet();
            List<Long> idList = new ArrayList<Long>();
            for(Data site : list) {
                    idList.add(site.getDbId());
            }
            // Here, you drop all ids that are not visible anymore
            // but before you had a chance to remove the marker
            keys.retainAll(idList);
    

    您可能想要在修改 keySet 之前对其进行复制。 你所说的 oldKeys 实际上是 newKeys。

    【讨论】:

    • 这是问题所在,我认为 KeySet 是一个独立的集合。 retainsAll 从列表中清除标记,但不是从地图中清除标记,因为它不会为每个想要从 HashMap 和 GoogleMap 中删除标记的人传递下一个,谢谢您的帮助
    猜你喜欢
    • 2012-12-10
    • 2019-12-04
    • 2018-04-13
    • 2021-04-20
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    相关资源
    最近更新 更多