如何使用 Xamarin 在 Android 中同步获取 GPS 位置更新?

Posted

技术标签:

【中文标题】如何使用 Xamarin 在 Android 中同步获取 GPS 位置更新?【英文标题】:How do I get a GPS location update synchronously in Android using Xamarin? 【发布时间】:2016-11-03 03:09:25 【问题描述】:

具体来说,我正在使用 Xamarin.Forms 进行 C# 开发,但是在原生 android 端编写 GPS 包装器类,该类将通过依赖注入在 Xamarin.Forms 端使用。就 Android 而言,C# 和 Java 之间的调用大部分应该是相同的。

基本上,我在 Android 端的 Geolocator 对象(实现 ILocationListener)中有这个方法:

public async Task<Tuple<bool, string, GPSData>> GetGPSData() 
        gpsData = null;
        var success = false;
        var error = string.Empty;

        if (!manager.IsProviderEnabled(LocationManager.GpsProvider)) 
            //request permission or location services enabling
            //set error
         else 
            manager.RequestSingleUpdate(LocationManager.GpsProvider, this, null);
            success = true;
        

        return new Tuple<bool, string, GPSData>(success, error, gpsData);
 

 public void OnLocationChanged(Location location) 
        gpsData = new GPSData(location.Latitude, location.Longitude);
    

我希望能够调用 GetGPSData 并让它返回元组,目前关于元组唯一重要的是填写 gpsData。我知道找到修复可能需要几秒钟,所以我想要这个方法一旦我真正需要该值,就可以在 Xamarin.Forms 端异步并等待。

我的问题是我无法找到让 manager.RequestSingleUpdate 同步工作的方法,或者任何解决方法。您调用该方法,然后最终 OnLocationChanged 触发。我试着扔了一个恶心的野蛮人

 while (gpsData == null);

在调用强制它不继续直到 OnLocationChanged 被触发之后,但是当我将该行放入时,OnLocationChanged 永远不会被调用。我假设这是因为 OnLocationChanged 是在同一个线程上调用的,而不是作为后台线程。

有什么方法可以让我接受这种情况并让 GetGPSData 在 OnLocationChanged 触发之前不返回?

谢谢

编辑:补充一点,这个方法不会被定期调用。这是自发的和罕见的,所以我不想使用 RequestLocationUpdates,获取定期更新并返回最新的更新,因为这需要始终打开 GPS,同时会不必要地耗尽电池。

【问题讨论】:

【参考方案1】:

您可以通过TaskCompletionSource 为所欲为。我遇到了同样的问题,这就是我解决它的方法:

TaskCompletionSource<Tuple<bool, string, GPSData> tcs;
// No need for the method to be async, as nothing is await-ed inside it.
public Task<Tuple<bool, string, GPSData>> GetGPSData() 
    tcs = new TaskCompletionSource<Tuple<bool, string, GPSData>>();
    gpsData = null;
    var success = false;
    var error = string.Empty;

    if (!manager.IsProviderEnabled(LocationManager.GpsProvider)) 
        //request permission or location services enabling
        //set error
        tcs.TrySetException(new Exception("some error")); // This will throw on the await-ing caller of this method.
     else 
        manager.RequestSingleUpdate(LocationManager.GpsProvider, this, null);
        success = true;
    

    //return new Tuple<bool, string, GPSData>(success, error, gpsData); <-- change this to:
    return this.tcs.Task;

还有:

public void OnLocationChanged(Location location) 
        gpsData = new GPSData(location.Latitude, location.Longitude);
        // Here you set the result of TaskCompletionSource. Your other method completes the task and returns the result to its caller.
        tcs.TrySetResult(new Tuple<bool, string, GPSData>(false, "someString", gpsData));
    

【讨论】:

工作就像一个魅力,非常感谢你。不过,对未来的人来说,在返回的任务上调用 Wait 将导致 OnLocationChanged 永远不会被调用(意味着没有设置任何任务结果),因为 OnLocationChanged 需要由调用 RequestSIngleUpdate 的同一线程调用。如果你阻塞线程,一切都会永远挂起。在结果上使用 ContinueWith() 来分配工作而不阻塞线程。 @Carson 或者,你可以这样做: var result = await GetGPSData();

以上是关于如何使用 Xamarin 在 Android 中同步获取 GPS 位置更新?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xamarin(iOS 和 Android)应用程序中使用 Windows 命名空间?

如何在 Xamarin Android 中使用 FontAwesome 图标

如何使用Xamarin在Visual Studio中创建Android应用

如何在 Xamarin/Android 上启用多个 BLE 特征通知?

如何在 Xamarin.Android 中使用 mipmap 文件夹?

如何在 Xamarin 中使用具有 android/IOS 特定视图的控制模板