如何修改Android定位代码 实现按需请求当前位置而非位置变化更新
按需主动获取位置实现方案
你现有代码存在两个基础问题:一是startListeningUserLocation方法没有完成位置监听注册(创建了LocationListener但没有传给LocationManager发起更新请求,实际无法收到位置回调);二是只有持续监听位置变化的逻辑,没有单次主动拉取位置的入口。不需要修改现有刷新时间、距离阈值,直接按以下方式修改即可实现按需获取:
- 补全原有持续监听的缺失逻辑,增加权限校验、资源释放方法,避免内存泄漏和异常
- 新增独立的主动获取位置方法,适配不同安卓版本的定位API,优先返回最新可用位置,拿到结果后自动停止监听减少耗电
- 增加权限缺失回调,方便业务层处理权限申请逻辑
修改后的完整LocationHelper代码
import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.os.Build import android.os.Bundle import android.os.CancellationSignal import androidx.core.app.ActivityCompat class LocationHelper { private val LOCATION_REFRESH_TIME = 3000L private val LOCATION_REFRESH_DISTANCE = 30f val MY_PERMISSIONS_REQUEST_LOCATION = 100 private var myLocationListener: MyLocationListener? = null private var mLocationManager: LocationManager? = null private var mLocationListener: LocationListener? = null // 自动选择当前可用的最高精度定位提供者 private val bestProvider: String get() { return mLocationManager?.let { when { it.isProviderEnabled(LocationManager.GPS_PROVIDER) -> LocationManager.GPS_PROVIDER it.isProviderEnabled(LocationManager.NETWORK_PROVIDER) -> LocationManager.NETWORK_PROVIDER else -> LocationManager.PASSIVE_PROVIDER } } ?: LocationManager.PASSIVE_PROVIDER } interface MyLocationListener { fun onLocationChanged(location: Location) fun onPermissionMissing() {} } /** * 原有持续监听位置变化的方法,补全注册逻辑 */ fun startListeningUserLocation(context: Context, myListener: MyLocationListener) { myLocationListener = myListener mLocationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager // 定位权限校验 if (ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { myLocationListener?.onPermissionMissing() return } mLocationListener = object : LocationListener { override fun onLocationChanged(location: Location) { myLocationListener?.onLocationChanged(location) } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } // 补全原代码缺失的监听注册逻辑 mLocationManager?.requestLocationUpdates( bestProvider, LOCATION_REFRESH_TIME, LOCATION_REFRESH_DISTANCE, mLocationListener!! ) } /** * 新增:按需主动获取当前单次位置 */ fun getCurrentLocation(context: Context, myListener: MyLocationListener) { mLocationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager // 定位权限校验 if (ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( context, Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { myListener.onPermissionMissing() return } val provider = bestProvider // 安卓11及以上用官方提供的主动拉取API,返回当前最新位置,不需要等待位置变化 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val cancellationSignal = CancellationSignal() mLocationManager?.getCurrentLocation(provider, cancellationSignal, context.mainExecutor) { location -> location?.let { myListener.onLocationChanged(it) } } } else { // 低版本先取系统缓存的最近位置,10秒内的缓存位置可直接使用,响应更快 val lastKnownLocation = mLocationManager?.getLastKnownLocation(provider) if (lastKnownLocation != null && System.currentTimeMillis() - lastKnownLocation.time < 10_000) { myListener.onLocationChanged(lastKnownLocation) return } // 缓存位置过期/不存在时,注册单次位置更新,拿到结果后自动停止 val singleUpdateListener = object : LocationListener { override fun onLocationChanged(location: Location) { myListener.onLocationChanged(location) mLocationManager?.removeUpdates(this) } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } mLocationManager?.requestSingleUpdate(provider, singleUpdateListener, context.mainLooper) } } /** * 页面销毁/不需要定位时调用,释放资源避免耗电和内存泄漏 */ fun stopLocationListening() { mLocationListener?.let { mLocationManager?.removeUpdates(it) } mLocationListener = null myLocationListener = null mLocationManager = null } }
调用方式
- 导航、轨迹记录这类需要持续接收位置更新的场景,继续使用原有
startListeningUserLocation方法即可,退出页面时记得调用stopLocationListening释放资源 - 打卡、位置信息上报这类只需要单次获取当前位置的场景,直接调用新增的
getCurrentLocation方法即可,不需要提前启动持续监听,也不会长期占用定位资源,示例代码:
LocationHelper().getCurrentLocation(this, object : LocationHelper.MyLocationListener { override fun onLocationChanged(location: Location) { val lat = location.latitude val long = location.longitude Log.d("Location","$lat,$long") // 拿到位置后写你的业务逻辑 } override fun onPermissionMissing() { // 处理无权限逻辑,比如弹定位权限申请 ActivityCompat.requestPermissions(this@YourActivity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LocationHelper().MY_PERMISSIONS_REQUEST_LOCATION) } })
注意:所有定位逻辑都需要先申请
ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限,权限未通过时无法获取位置;安卓12及以上需要后台定位的话,要额外申请ACCESS_BACKGROUND_LOCATION权限。主动获取位置的逻辑和持续监听完全独立,不受你配置的刷新时间、距离阈值影响。
内容的提问来源于stack exchange,提问作者helpVulcan
相关产品推荐
相关产品推荐

