How to synchronously request a single GPS location update?

SunliMinSunliMin CAMember ✭✭
edited July 2016 in Xamarin.Forms

I am writing a Xamarin.Forms application, but since GPS is not part of Xamarin.Forms, I am using dependency injection to get a native Android and iOS implementation of it. I am currently trying to get the Android side working and will focus on all the iOS work once Android is done.

Essentially, what I want to do is have this:

public async Task<Tuple<bool, string, GPSData>> GetGPSData() {
        gpsData = null;
        bool success = false;
        string error = string.Empty;

        if (!manager.IsProviderEnabled(LocationManager.GpsProvider)) {
            //request permission or location services enabling
            //Handle any error messages, store in variable string
        } else {
            manager.RequestSingleUpdate(LocationManager.GpsProvider, this, null);
            success = true; //Assuming this worked
        }

        return new Tuple<bool, string, GPSData>(success, error, gpsData.Value);
    }

Be a method in my IGeolocator implementation (which also extends ILocationListener on Android). It should return a Task that is a Tuple of bool, string and GPSData, where bool is true/false on whether it was a success grabbing the data, the string is the error message if the bool was false, and if it was true GPSData is not null, which is simply a wrapper around the data that is found in Androids Location object.

Before I do the error checking and such I just want to return a GPS location, hence the hard-coded return value.

The problem is that RequestSingleUpdate runs asynchronously, so when it is invoked long after the method returns. I want to handle multi threading on the Xamarin.Forms side outside of this method call. Really, ideally I'd like to simply await manager.RequestSingleUpdate.

I thought about throwing in a hacky

while(gpsData == null);

after it requests so that it blocks that thread until OnLocationChanged is invoked and sets gpsData, however it seems when I do this, it is never invoked. OnLocationChanged only ever gets invoked if I let my GetGPSData() function return.

Is there any way of my getting my gpsData set (AKA OnLocationChanged invoked) BEFORE this method returns?

Thank you for your time.

Best Answers

Answers

  • JulienRosenJulienRosen CAMember ✭✭✭✭

    Really, ideally I'd like to simply await manager.RequestSingleUpdate.

    so await it?

    await manager.RequestSingleUpdate(LocationManager.GpsProvider, this, null);

    your method is already marked async but i see no awaits...

  • SunliMinSunliMin CAMember ✭✭

    You can't await RequestSingleUpdate as it returns a void and is not async.

    I know my method is marked async. I'm assuming it will need to be async to return the Task in the way I want, however it's not complete, hence why I'm asking the question.

    Essentially, RequestSingleUpdate notifies the ILocationListener (the object with my GetGPSData method) to start listening for a GPS request and invoke the OnLocationChanged method when a GPS request is being served.

    The issue is that OnLocationChanged even isn't fired right away, it takes time.

    What I want to do is essentially do the equivalent of "await" the RequestSingleUpdate (or anything, not that specific method since it's not awaitable) so the method won't return until OnLocationChanged managed to get fired off.

    It's fine if the method hangs to accomplish this as this is being invoked from a threaded portion of my program.

  • SunliMinSunliMin CAMember ✭✭

    So here's the thing...

    I have it working where GetGPSData takes in a callback Action that is stored, and OnLocationChanged it fires off this action. This works 100% perfectly.

    The issue is my supervisor does not like it and wants me to change this to return a task. He wants me to make this asynchronous. I feel like it's impossible with the way Android utilizes the GPS system, however he wants me to do it that way and told me nothing is impossible, so I figured I must be missing a part of the puzzle.

    I'm gonna go ahead and accept your answer cause I know it works and it will work for future people who see this thread. However, sadly due to politics, it doesn't really help me even though it should.

  • JulienRosenJulienRosen CAMember ✭✭✭✭

    If RequestSingleUpdate raises an event when it completes, it is async already. Not really sure what you want returning a task or what that task should be.

Sign In or Register to comment.