具体来说,我正在使用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);

在调用之后,强制它在onlocationchange被激发之前不继续,但是当我放入该行时,onlocationchange永远不会被调用。我假设这是因为onlocationchanged是在同一个线程上调用的,而不是后台线程。
有没有什么方法可以让我在onlocationchange启动之前不返回getgpsdata?
谢谢
编辑:要添加,此方法将不定期调用。这是自发和罕见的,所以我不想使用requestLocationUpdates,获取定期更新并返回最新的更新,因为这需要始终打开GPS,同时会不必要地雨电池。

最佳答案

你可以用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));
    }

09-13 11:14