Xamarin.Forms DependencyService difficulty getting location
Asked Answered
F

4

4

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

Felice answered 1/9, 2014 at 8:21 Comment(1)
I got an error in "Geolocator locator" declaration. I have added nuget package "Plugin.Geolocator".Consumedly
U
3

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());
    }
}
Unscrew answered 2/9, 2014 at 1:18 Comment(20)
Thanks jendsendp, I am trying your version now, I have a couple of issues still, but I suspect it is where I am calling it -Felice
Getting a list of errors starting with System.AggregateException: ---> Java.Lang.IllegalStateException, will do some researchFelice
Are you getting the error in the code referenced above or somewhere else in your code?Unscrew
it is in GetPosition (I changed it to Task(Position> GetPosition()Felice
Java.Lang.IllegalStateExceptionFelice
at Android.Content.ContextWrapper.GetSystemService (System.String name) [0x0007e] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.14-series/a5d57087/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.Content.ContextWrapper.cs:1823Felice
at Xamarin.Geolocation.Geolocator..ctor (Android.Content.Context context) [0x0001f] in c:\BuildAgent\work\bb79242ef4f930a5\MonoDroid\Xamarin.Mobile\Geolocation\Geolocator.cs:36Felice
--- End of managed exception stack trace --- 09-02 14:15:20.123 D/GeolocatorError( 5197): java.lang.IllegalStateException: System services not available to Activities before onCreate()Felice
I believe the problem is with your use of the Geolocator constructor. You are trying to pass in "this" as the context as if you were truly an "Activity", but since you are using Xamarin.Forms that may not work as expected. Instead, Xamarin.Forms give you access to the "Context" through the "Context" property on the Forms class. Try this instead: "locator = new Geolocator(Forms.Context);"Unscrew
Thanks once again for your reply. I have changed this to Forms.Context but now it just hangs, no error - just nothing.Felice
Where does the execution seem to stop? In the suggested code or in code outside of this. Can I see how you are calling this code?Unscrew
here is the call: Task<MyLocation> taskLocation = DependencyService.Get<ICurrentLocation>().GetCurrentLocation(); location = taskLocation.Result; and when i step through the code, it reaches here and hangs position = await locator.GetPositionAsync(timeout: 10000);Felice
I think you are running into a deadlock situation. Since GetCurrentLocation is an "async" method, you will need to "await" it. To do that you will need to make the method that contains this code "async" in the method signature. Then you will be able to set "location = taskLocation" or just use "taskLocation" and you won't have to worry about the ".Result".Unscrew
Thanks, once again jensendp, I will give it a shot after work and let you know how I goFelice
Thankyou jensendp, for all your help (and your patience), it finally works.Felice
Excellent, glad we figured it out. Hope you app turns out great!Unscrew
I'm petty sure that I'll still be requiring some help, I am a middle aged uni student working on a project with limited time - a great learning experience though - you are being referenced!Felice
It's never too late to be a student. I'm not in school, but I consider myself an eternal student to those around me. Feel free to reach out to me if you ever need any help. I'm more than happy to be of assistance.Unscrew
Thankyou - i will probably take you up on that offerFelice
I got an error in "Geolocator locator" declaration. I have added nuget package "Plugin.Geolocator".Consumedly
C
2

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

Carleycarli answered 2/9, 2014 at 0:52 Comment(1)
Thanks for your reply, I started with the Xamarin-Forms-Labs example, but as a complete newbie, I couldn't follow it at all. I am at the beginning of a crash course in C#, Xamarin etcFelice
B
0

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

Bluegreen answered 1/9, 2014 at 8:21 Comment(2)
Thanks for your response. I have looked up await/async - as far as I can tell the method using it must either return void or a Task, how could I return MyLocation? this is all completely new to me, can you show me how to implement it? Also, I already have the assembly above the namespace in the Android file, do I need to put it somewhere else as well?Felice
You can use the generic Task class. return something like Task<MyLocation>.Unscrew
M
0

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);
        }
    }
Mingy answered 4/10, 2022 at 17:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.