You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何删除地图旧标记并基于JSON数据展示新标记?

解决其他位置标记更新问题及代码优化建议

一、删除旧标记并显示新标记的解决方案

你当前的问题核心是没有保存所有其他位置的标记引用——原来的代码里otherMarkers变量每次循环都会被覆盖,只保留最后一个标记,自然无法删除之前的所有旧标记。只需要做以下两步修改就能解决:

1. 添加成员变量存储所有其他标记

在你的MapsActivity类中,新增一个集合来保存所有其他位置的Marker实例:

// 用来存储所有其他位置的标记,方便后续批量删除
private List<Marker> otherMarkersList = new ArrayList<>();

2. 修改onPostExecute方法,先清旧标记再添新标记

更新LocationSearchTaskonPostExecute逻辑,每次获取新数据后,先清空所有旧标记,再添加新标记并存入集合:

@Override
protected void onPostExecute(List<User> users) {
    try {
        // 第一步:删除所有旧的其他位置标记
        for (Marker marker : otherMarkersList) {
            marker.remove();
        }
        otherMarkersList.clear();
        
        // 第二步:添加新标记并保存到集合中
        for (User user : users) {
            LatLng position = new LatLng(user.getLat(), user.getLng());
            Marker newMarker = mMap.addMarker(new MarkerOptions()
                    .position(position)
                    .title(user.getFirstName())
                    .icon(bitmapDescriptorFromVector(getApplicationContext(), R.mipmap.ic_navigation))
                    .snippet(user.getEmail()));
            otherMarkersList.add(newMarker);
        }
    } catch (Exception e) {
        Toast.makeText(MapsActivity.this, "Sorry other locations are unavailable! Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
    }
}

这样每次调用updateOtherLocations()时,旧标记会被全部清除,再显示最新的位置标记,就和你当前位置的更新逻辑一致了。


二、代码优化建议

你的功能已经跑通,但还有几个可以提升稳定性、性能的优化点:

  • 替换AsyncTask,使用现代网络框架:AsyncTask已经被Android官方废弃,推荐用RetrofitOkHttp处理网络请求,它们支持请求取消、拦截器、线程管理等更完善的功能,稳定性也更好。
  • 修复后台线程弹Toast的问题doInBackground是后台线程,直接调用Toast会报错(Toast必须在UI线程执行)。建议把异常信息传递到onPostExecute再显示:
    private Exception requestException;
    
    @Override
    protected List<User> doInBackground(String... urls) {
        try {
            if (urls.length < 1 || urls[0] == null) {
                return null;
            }
            return QueryData.fetchUsersData(urls[0]);
        } catch (Exception e) {
            requestException = e;
            return null;
        }
    }
    
    @Override
    protected void onPostExecute(List<User> users) {
        if (requestException != null) {
            Toast.makeText(MapsActivity.this, "Error: " + requestException.getMessage(), Toast.LENGTH_SHORT).show();
            return;
        }
        // 后续标记处理逻辑...
    }
    
  • 添加位置更新防抖机制onLocationChanged可能频繁触发(比如每秒多次),导致频繁发起网络请求。可以设置距离阈值(比如位置变化超过100米)或时间间隔(比如每5秒)再更新其他位置:
    private static final float UPDATE_DISTANCE_THRESHOLD = 100; // 100米
    private Location lastUpdatedLocation;
    
    @Override
    public void onLocationChanged(Location location) {
        Log.i(TAG, location.toString());
        // 只有位置变化超过阈值才更新
        if (lastUpdatedLocation == null || location.distanceTo(lastUpdatedLocation) > UPDATE_DISTANCE_THRESHOLD) {
            lastUpdatedLocation = location;
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            LatLng latLng = new LatLng(latitude, longitude);
            if (currentMarker != null) {
                currentMarker.remove();
            }
            displayLocation(latLng, 15f, location);
            updateOtherLocations();
        }
    }
    
  • 完善权限处理:确保checkPermission()不仅检查权限,还在权限被拒绝时引导用户开启权限,避免后续功能直接失效。
  • 避免内存泄漏:在Activity销毁时,取消正在执行的网络请求,同时清空标记集合和当前标记:
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消未完成的网络请求(如果用Retrofit则取消Call实例)
        if (locationSearchTask != null && !locationSearchTask.isCancelled()) {
            locationSearchTask.cancel(true);
        }
        // 清理标记
        if (currentMarker != null) {
            currentMarker.remove();
        }
        for (Marker marker : otherMarkersList) {
            marker.remove();
        }
        otherMarkersList.clear();
    }
    
  • 复用Marker图标bitmapDescriptorFromVector每次创建新的BitmapDescriptor会浪费内存,建议在onCreate中提前创建一次并复用:
    private BitmapDescriptor navigationIcon;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // 提前初始化图标,后续直接复用
        navigationIcon = bitmapDescriptorFromVector(getApplicationContext(), R.mipmap.ic_navigation);
        // 其他初始化逻辑...
    }
    

内容的提问来源于stack exchange,提问作者Kutubek Kylychbekov

火山引擎 最新活动