Skip to content

Instantly share code, notes, and snippets.

@alexshikov
Last active April 25, 2016 19:56
Show Gist options
  • Save alexshikov/153de5d46ffb9a06fae778110e0ce864 to your computer and use it in GitHub Desktop.
Save alexshikov/153de5d46ffb9a06fae778110e0ce864 to your computer and use it in GitHub Desktop.
Example of Task based LocationService implementation using Mvx Location Plugin
public interface ILocationService
{
Coordinates GetLastSeenLocation();
Task<Coordinates> GetCurrentLocation ();
}
public class LocationService : ILocationService
{
private const string Tag = "LocationService";
private readonly object _lock = new object();
private static readonly TimeSpan timeOut = TimeSpan.FromSeconds (10);
private TaskCompletionSource<Coordinates> taskSource;
private readonly IMvxLocationWatcher locationWatcher;
private readonly IMvxMainThreadDispatcher dispatcher;
public LocationService (IMvxLocationWatcher locationWatcher, IMvxMainThreadDispatcher dispatcher)
{
this.locationWatcher = locationWatcher;
this.dispatcher = dispatcher;
this.locationWatcher.OnPermissionChanged += PermissionChanged;
}
public Coordinates GetLastSeenLocation()
{
var location = locationWatcher.LastSeenLocation;
if (location == null)
{
return Coordinates.Empty;
}
return new Coordinates(location.Coordinates.Latitude, location.Coordinates.Longitude);
}
public Task<Coordinates> GetCurrentLocation()
{
Task<Coordinates> task;
bool startWatcher = false;
lock (_lock)
{
if (taskSource == null)
{
taskSource = new TaskCompletionSource<Coordinates>();
startWatcher = true;
}
task = taskSource.Task;
}
if (startWatcher)
{
StartWatcher();
}
return task;
}
private void StartWatcher ()
{
Trace.Debug (Tag, "StartWatcher");
dispatcher.RequestMainThreadAction(() =>
{
if (locationWatcher.Started) {
Trace.Warn (Tag, "Watcher already started!");
return;
}
locationWatcher.Start(new MvxLocationOptions() { Accuracy = MvxLocationAccuracy.Coarse },
location =>
{
locationWatcher.Stop();
OnSuccess (new Coordinates(location.Coordinates.Latitude, location.Coordinates.Longitude));
},
error =>
{
locationWatcher.Stop();
OnError (new LocationException(error.Code));
});
Task.Delay (timeOut).ContinueWith (_ => OnTimeout ());
});
}
private void OnTimeout ()
{
Trace.Debug(Tag, "Timeout");
TaskCompletionSource<Coordinates> source;
lock (_lock)
{
source = taskSource;
taskSource = null;
}
source?.SetException (new LocationException (MvxLocationErrorCode.Timeout));
if (locationWatcher.Started) {
locationWatcher.Stop();
}
}
private void OnSuccess (Coordinates coordinates)
{
Trace.Debug(Tag, "Updated: " + coordinates);
TaskCompletionSource<Coordinates> source;
lock (_lock)
{
source = taskSource;
taskSource = null;
}
source?.SetResult(coordinates);
}
private void OnError (LocationException error)
{
Trace.Warn(Tag, "Error: " + error.Code.ToString());
TaskCompletionSource<Coordinates> source;
lock (_lock)
{
source = taskSource;
taskSource = null;
}
source?.SetException(error);
}
private void PermissionChanged (object sender, MvxValueEventArgs<MvxLocationPermission> e)
{
Trace.Warn(Tag, "Permission changed: " + e.Value.ToString ());
if (e.Value != MvxLocationPermission.Denied)
{
return;
}
// Process only if denied
TaskCompletionSource<Coordinates> source;
lock (_lock)
{
source = taskSource;
taskSource = null;
}
source?.SetException(new LocationException (MvxLocationErrorCode.PermissionDenied));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment