You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
          }
   }
}

解决方案

问题根源

你的代码存在两个关键错误:

  1. 类型转换错误:GetCurrentLocation返回的是Android原生的Android.Locations.Location对象,而非Microsoft.Maui.Devices.Sensors.Location,强行跨类型转换会导致匹配失败。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:13:13