Kotlin中Google Map位置更新时移动Marker而非重复添加的实现方法
解决Google Maps Android重复添加Marker的问题:复用单个Marker
这是个很常见的新手坑——每次位置更新就新建Marker确实会导致地图上堆一堆标记,咱们只需要在类里持有一个唯一的Marker实例,就能实现“只保留首个Marker并在位置更新时移动它”的需求。
步骤1:声明类级别的Marker变量
首先在你的Activity/Fragment里,定义一个可空的Marker变量,用来保存咱们要复用的那个标记:
private var userLocationMarker: Marker? = null
步骤2:在位置更新回调中处理Marker
假设你用的是FusedLocationProviderClient获取位置更新,或者在onLocationChanged回调里处理位置数据,拿到新的Location后先转换成LatLng,再判断Marker是否存在:
// 处理新位置的方法 private fun onNewLocationReceived(location: Location) { val newLatLng = LatLng(location.latitude, location.longitude) // 检查Marker是否已存在 userLocationMarker?.let { existingMarker -> // 若已存在,直接更新它的位置 existingMarker.position = newLatLng } ?: run { // 若不存在,创建新Marker并赋值给变量 userLocationMarker = mMap.addMarker( MarkerOptions() .position(newLatLng) .title("我的位置") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)) ) } // 可选:同时移动地图相机到新位置,提升用户体验 mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newLatLng, 15f)) }
关键注意点
- 确保
mMap对象已初始化完成(必须在onMapReady(googleMap: GoogleMap)回调里赋值),否则调用addMarker会触发空指针异常。 - Marker的自定义样式(图标、标题等)只需要在首次创建时设置,后续更新位置不会改变这些属性。
- 如果需要移除这个Marker,直接调用
userLocationMarker?.remove(),再把变量置为null即可。
完整示例片段(结合MapReady回调)
class MapsActivity : AppCompatActivity(), OnMapReadyCallback { private lateinit var mMap: GoogleMap private var userLocationMarker: Marker? = null private lateinit var fusedLocationClient: FusedLocationProviderClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_maps) // 初始化地图Fragment val mapFragment = supportFragmentManager .findFragmentById(R.id.map) as SupportMapFragment mapFragment.getMapAsync(this) // 初始化位置服务客户端 fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) } override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap // 开启我的位置图层(可选) mMap.isMyLocationEnabled = true // 启动位置更新监听 startLocationUpdates() } private fun startLocationUpdates() { // 配置位置更新参数 val locationRequest = LocationRequest.create().apply { interval = 10000 // 10秒更新一次 fastestInterval = 5000 // 最快5秒更新一次 priority = LocationRequest.PRIORITY_HIGH_ACCURACY } // 权限检查(记得在Manifest添加权限,并在运行时申请) if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationClient.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } } // 位置更新回调 private val locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { super.onLocationResult(locationResult) locationResult.lastLocation?.let { location -> onNewLocationReceived(location) } } } private fun onNewLocationReceived(location: Location) { val newLatLng = LatLng(location.latitude, location.longitude) userLocationMarker?.let { existingMarker -> existingMarker.position = newLatLng } ?: run { userLocationMarker = mMap.addMarker( MarkerOptions() .position(newLatLng) .title("我的位置") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)) ) } mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newLatLng, 15f)) } // Activity销毁时移除位置更新监听 override fun onDestroy() { super.onDestroy() fusedLocationClient.removeLocationUpdates(locationCallback) } }
这样就能实现每次位置更新时,只移动已有的Marker,而不会重复创建新标记了。
内容的提问来源于stack exchange,提问作者hdiz
相关产品推荐
相关产品推荐

