How to use xamarin to synchronize GPS location updates in Android?
Specifically, I am using xamarin.forms for c# development, but I work on native Android and write a GPS wrapper class, which can be used in xamarin.forms through dependency injection. In most cases, the calls between Android, c# and Java should be the same
In essence, I have this method in the geolocator object (implementing ilocationlister) on the Android side:
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);
}
and
public void OnLocationChanged(Location location) {
gpsData = new GPSData(location.Latitude, location.Longitude);
}
I hope to call getgpsdata and let it return tuples. At present, the only important thing about tuples is that GPSdata has been filled. I know it may take a few seconds to find the repair method, so I hope this method is asynchronous. Once I really need the value, I can wait at xamarin.forms
My problem is that I can't think of a way for manager.requestsingleupdate to synchronize or do other work. You call this method and eventually trigger onlocationchanged. I tried to throw a disgusting barbarian
while (gpsData == null);
After the call that forces it not to continue until onlocationchanged is triggered, but when I put the row in, onlocationchanged will never be called. I assume this is because onlocationchanged is called on the same thread rather than the background thread
What can I do to take this situation and not return getgpsdata before onlocationchanged is triggered?
thank you
Edit: to add, this method will not be called periodically. It is spontaneous and rare, so I don't want to use requestlocationupdates to get regular updates and return the latest updates, because it will need to always turn on GPS and unnecessarily rain the battery
resolvent:
You can use taskcompletionsource to perform the required operations. I have encountered the same problem. This is my solution:
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;
}
And:
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));
}