user1667474
user1667474

Reputation: 819

Xamarin.Forms DependencyService difficulty getting location

So after finally getting my head around Xamarin.Forms DependencyService I have nearly got it returning the device's current location.

my interface

public interface ICurrentLocation
{
    MyLocation SetCurrentLocation();
}

MyLocation

public class MyLocation
{
    public double Latitude {get; set;}
    public double Longitude{get; set;}
}

the line that calls it

MyLocation location = DependencyService.Get<ICurrentLocation>().SetCurrentLocation();

and in the CurrentLocation class in the Android project that implements the Geolocation class of Xamarin.Mobile

[assembly: Dependency(typeof(CurrentLocation))]
namespace MyCockburn.Droid
{

    public class CurrentLocation : Activity, ICurrentLocation

        Geolocator locator;
        Position position = new Position();
        MyLocation location;

        public MyLocation SetCurrentLocation()
        {
            GetPosition();
            location = new MyLocation()
            {
                Latitude = position.Latitude,
                Longitude = position.Longitude
            };


            return location;
       }

       async void GetPosition()
       {
           try
           {
                 locator = new Geolocator(this) { DesiredAccuracy = 50 };
                 if (locator.IsListening != true)
                       locator.StartListening(minTime: 1000, minDistance: 0);

                 position = await locator.GetPositionAsync(timeout: 20000);

           }
           catch (Exception e)
           {
               Log.Debug("GeolocatorError", e.ToString());
           }
       }
   }

my problem seems to be that is returning location before position holds the longitude and latitude

I am hoping my mistake is glaringly obvious

EDIT: the code works if I run it as a normal Android Activity

Upvotes: 4

Views: 5338

Answers (4)

Momodu Deen Swarray
Momodu Deen Swarray

Reputation: 169

I developed an app that works fine in getting GPS location. I believe the codes below will be of great help.

You can then edit the SubmitGPSLocation function to your preference.

 public async Task Run(CancellationToken token)
    {
        await Task.Run(async () =>
        {
            if (GPSService.Instance.IsListening)
            {
                GPSService.Instance.StopListening();
            }

            GPSService.Instance.StartListening(2500, 50, true); 
            GPSService.Instance.PositionChanged += Instance_PositionChanged;

            System.Diagnostics.Debug.WriteLine(getRunningStateLocationService());

            while (getRunningStateLocationService())
            {
                token.ThrowIfCancellationRequested();                   
                await Task.Delay(500).ConfigureAwait(true);
            }

            GPSService.Instance.StopListening();
          
            //await CrossGeolocator.Current.StopListeningAsync().ConfigureAwait(true);
            GPSService.Instance.PositionChanged -= Instance_PositionChanged;

            return;
        }, token).ConfigureAwait(false);
    }


    private void Instance_PositionChanged(object sender, PositionEventArgs e)
    {
        try
        {
            isEvenCount = !isEvenCount;

            if (e.Position != null)
            { 
                var message = new LocationMessage
                {
                    Latitude = e.Position.Latitude,
                    Longitude = e.Position.Longitude,
                    Accuracy = e.Position.Accuracy,
                    Speed = e.Position.Speed,
                    Heading = e.Position.Heading,
                    TimeStamp = e.Position.Timestamp.DateTime
                };

                SubmitGPSLocation(e).ConfigureAwait(false);
            }
            else
            {
                CrossToastPopUp.Current.ShowToastMessage("Failed to get GPS location");
             }
        }
        catch (Exception ex)
        {
            CrossToastPopUp.Current.ShowToastMessage(ex.Message);
        }
    }


    private static async Task SubmitGPSLocation(PositionEventArgs e)
    {
        if (!NetworkCheck.IsInternet())
        {
            return;
        }

        if (!int.TryParse(App.PhoneID, out var number))
        {
            return;
        }

        try
        {
            var thetrackers = Convert.ToString(Application.Current.Properties["AuthorizedTrackers"]);

            GeneralUserPhoneLocation MyGeneralUserPhoneLocation = new GeneralUserPhoneLocation();
            MyGeneralUserPhoneLocation.PhoneID = int.Parse(App.PhoneID);
            MyGeneralUserPhoneLocation.Latitude = e.Position.Latitude.ToString("n6");
            MyGeneralUserPhoneLocation.Longitude = e.Position.Longitude.ToString("n6");

            MyGeneralUserPhoneLocation.Accuracy = e.Position.Accuracy;
            MyGeneralUserPhoneLocation.Heading = e.Position.Heading;
            MyGeneralUserPhoneLocation.Speed = e.Position.Speed;
            MyGeneralUserPhoneLocation.TimeStamp = e.Position.Timestamp.DateTime;

            MyGeneralUserPhoneLocation.RequestType = "N";
            MyGeneralUserPhoneLocation.Comment = thetrackers;

            string servicestring = JsonConvert.SerializeObject(MyGeneralUserPhoneLocation);
            HttpContent theusercontent = new StringContent(servicestring, Encoding.UTF8, "application/json");

            using (HttpClient client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://mygpswebapi.com");
                var response = await client.PostAsync("Home/SaveGeneralUserPhoneLocationAPP/", theusercontent).ConfigureAwait(true);

                if (response.IsSuccessStatusCode)
                {
                   
                }
                else
                {
                }
            }
        }
        catch (Exception ex)
        {
            CrossToastPopUp.Current.ShowToastMessage(ex.Message);
        }
    }

Upvotes: 0

jensendp
jensendp

Reputation: 2135

I would do a slight modification since best practice is to either do all async or none. When you try to return the result from an async method from a non async method you can run into problems with deadlocks. Also, since you aren't using the await keyword when calling the GetPosition method, you are getting back a Task, but aren't checking when the operation is complete. I suggest slightly modifying your code as such.

public interface ICurrentLocation {
    Task<MyLocation> GetCurrentLocation();
}

public async Task<MyLocation> GetCurrentLocation()
{
    var position = await GetPosition();
    return new MyLocation()
    {
        Latitude = position.Latitude,
        Longitude = position.Longitude
    };
}

async Task<Location> GetPosition()
{
    try
    {
          locator = new Geolocator(this) { DesiredAccuracy = 50 };
          if (locator.IsListening != true)
                locator.StartListening(minTime: 1000, minDistance: 0);

          return await locator.GetPositionAsync(timeout: 20000);

    }
    catch (Exception e)
    {
        Log.Debug("GeolocatorError", e.ToString());
    }
}

Upvotes: 3

SKall
SKall

Reputation: 5234

You aren't waiting for the position function to finish. Many different options and keeping it async is the best one but if you want it synchronous then try this blocking call:

   void GetPosition()
   {
       try
       {
             locator = new Geolocator(this) { DesiredAccuracy = 50 };
             if (locator.IsListening != true)
                   locator.StartListening(minTime: 1000, minDistance: 0);

             position = locator.GetPositionAsync(timeout: 20000).Result;

       }
       catch (Exception e)
       {
           Log.Debug("GeolocatorError", e.ToString());
       }
   }

I also recommend taking a look at Xamarin.Forms.Labs as it already has abstracted GPS service and working sample that is functional for all 3 platforms:

https://github.com/XForms/Xamarin-Forms-Labs

Upvotes: 2

Arthur Csertus
Arthur Csertus

Reputation: 43

Try adding the assembly above the namespace and awaiting the GetPosition method.

Take a look at this image: http://developer.xamarin.com/guides/cross-platform/xamarin-forms/dependency-service/Images/solution.png

Upvotes: 0

Related Questions