Android/Maui中用C#调用LocationManager.GetCurrentLocation()的方法
问题:Android API 30+中LocationManager.GetCurrentLocation()的IConsumer在C#中的正确实现
背景与问题
我有一个前台服务,通过RequestLocationUpdates每隔n秒获取GPS位置,正常运行无问题,但手机进入省电模式且屏保激活时失效。我尝试用AlarmManager解决:闹钟唤醒应用后检查GPS时间戳,若时间戳较旧则重新获取位置,否则创建新闹钟循环执行。
试过Xamarin.Essentials和Microsoft.Maui相关API,但它们在省电模式下无法返回位置信息。现在希望使用API 30及以上的LocationManager.GetCurrentLocation()获取单次GPS位置——前台服务已在休眠前预热GPS并完成定位,无需等待定位过程。
核心问题:最后一个参数IConsumer在C#中该如何正确实现?
我尝试的代码(无法正常工作)
{ var location = _locationManager?.GetCurrentLocation( LocationManager.GpsProvider, null, ContextCompat.GetMainExecutor(Application.Context), locationCallback); } private Consumer<Microsoft.Maui.Devices.Sensors.Location> locationCallback = new MyLocationCallback(); private class MyLocationCallback : Java.Lang.Object, Java.Util.Functions.IConsumer { public void Accept(Java.Lang.Object p0) { Microsoft.Maui.Devices.Sensors.Location location = (Microsoft.Maui.Devices.Sensors.Location)p0; if (location != null) { //Do something with location } } }
解决方案
问题根源
你的代码存在两个关键错误:
- 类型转换错误:
GetCurrentLocation返回的是Android原生的Android.Locations.Location对象,而非Microsoft.Maui.Devices.Sensors.Location,强行跨类型转换会导致匹配失败。 - IConsumer泛型实现错误:在Xamarin/C#中实现Java的
IConsumer时,需要明确指定原生Location泛型类型,避免类型混淆。
正确的IConsumer实现
方式1:独立类实现泛型IConsumer
// 声明回调对象 private Java.Util.Functions.IConsumer<Android.Locations.Location> _locationCallback; // 在服务初始化或启动时初始化回调 _locationCallback = new LocationConsumer(); // 调用GetCurrentLocation var locationTask = _locationManager?.GetCurrentLocation( LocationManager.GpsProvider, null, // 可按需传入LocationRequest参数,控制定位精度/超时 ContextCompat.GetMainExecutor(Application.Context), _locationCallback); // 实现IConsumer<Location>的内部类 private class LocationConsumer : Java.Lang.Object, Java.Util.Functions.IConsumer<Android.Locations.Location> { public void Accept(Android.Locations.Location location) { if (location != null) { // 可选:将原生Location转换为MAUI Location对象 var mauiLocation = new Microsoft.Maui.Devices.Sensors.Location { Latitude = location.Latitude, Longitude = location.Longitude, Accuracy = location.Accuracy, Timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(location.Time) }; // 执行你的业务逻辑 // Do something with mauiLocation or raw location } else { // 处理定位失败逻辑,比如重新发起请求或记录日志 } } }
方式2:匿名类简化实现(适合单次使用场景)
如果不需要复用回调逻辑,可以直接用匿名类实现:
_locationManager?.GetCurrentLocation( LocationManager.GpsProvider, null, ContextCompat.GetMainExecutor(Application.Context), new Java.Util.Functions.IConsumer<Android.Locations.Location> { Accept = location => { if (location != null) { // 直接处理原生Location对象 } // 定位失败的处理逻辑 } });
额外注意事项
- 权限适配:API 30+需确保已申请
ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION,后台定位场景还需申请ACCESS_BACKGROUND_LOCATION,并处理动态权限请求。 - 省电模式兼容:部分厂商的省电策略可能仍会限制GPS访问,建议保持前台服务的通知可见,并引导用户将应用加入系统省电白名单。
- 取消定位请求:可以传入
CancellationSignal作为第二个参数,用于在需要时主动取消定位请求,避免不必要的资源消耗。
内容的提问来源于stack exchange,提问作者JohnJore
相关产品推荐
相关产品推荐

