具体来说,我正在使用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而不是后台线程。
有没有办法让我采用这种情况,并且在OnLocationChanged被解雇之前不会返回GetGPSData?
由于
编辑:要添加,不会定期调用此方法。它是自发的和罕见的,所以我不想使用RequestLocationUpdates,定期更新并返回最新的更新,因为这需要始终打开GPS,同时会不必要地耗尽电池。
答案 0 :(得分:3)
您可以使用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));
}