开发者

Location service returning previous coordinates on WP7

开发者 https://www.devze.com 2023-03-10 08:22 出处:网络
I\'m using the code from the official site, and I am consistently seeing the same behavior on multiple test devices - instead of getting the current location of the device, it gets the previous locati

I'm using the code from the official site, and I am consistently seeing the same behavior on multiple test devices - instead of getting the current location of the device, it gets the previous location (up to 30 miles away, where I was an hour ago).

        private void setupMaps()
        {
            watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            watcher.MovementThreshold = 10.0f;

            watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_statusChanged);
            watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

            new Thread(startLocServInBackground).Start();
        }

        void startLocServInBackground()
        {
            watcher.TryStart(true, TimeSpan.FromSeconds(60));
        }

        void watcher_statusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    // The Location Service is disabled or unsupported.
                    // Check to see if the user has disabled the location service.
                    if (watcher.Permission == GeoPositionPermission.Denied)
                    {
                        // the user has disabled LocServ on their device.
                        showMessage("Location is required but it is disabled. Turn it on in Settings");
                    }
                    else
                    {
                        showMessage("Location is not functioning on this phone. Sorry, Crux cannot run");
                    }
                    break;

                case GeoPositionStatus.Initializing:
                    // The location service is initializing.
                    LoadingInfo.Text = "finding location";
                    break;

                case GeoPositionStatus.NoDa开发者_运维技巧ta:
                    // The Location Service is working, but it cannot get location data
                    // due to poor signal fidelity (most likely)

                    // this fired intermittently when data was coming back :/
                    //MessageBox.Show("Location data is not available.");

                    break;

                case GeoPositionStatus.Ready:
                    // The location service is working and is receiving location data.
                    //statusTextBlock.Text = "Location data is available.";
                    LoadingInfo.Text = "Location found";
                    // THIS FIRES AFTER POSITION CHANGED HAS STOPPED FIRING
                    break;
            }
        }

        private void initPostPanel()
        {
            PostPanel.Visibility = Visibility.Visible;
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            // update the textblock readouts.
            latitude = e.Position.Location.Latitude.ToString("0.0000000000");
            longitude = e.Position.Location.Longitude.ToString("0.0000000000");
            // THIS FIRES TWICE, BEFORE STATUS IS FIRED AS READY. THEN THIS DOESN'T CALL AGAIN
        }

What I would expect to have happen is to get a continuous series of calls to PositionChanged after StatusChanged is called with a Status of Ready. If the calls continued after Ready, I expect I would eventually get the correct coordinates - but it never calls after that point.

This does not occur with the emulator, only on the actual device (making this extremely difficult to test - since it actually involves driving between each test!)

I am running the source code from the tutorial as well, and it does roughly the same.

Can anyone tell me more about the expected behavior here and how I get what I need - which is simply a set of coordinates for the device at the current location when the app is being used.


I had the same problem myself - there are 2 parts to this.

Turns out the GeoCoordinateWatcher returns the last known good position - which is almost always out of date. What I do is something like this: Check that the status is GeoPositionStatus.Ready and then ensure the datetime of the position is recent (within the last 5 mins). You can then go further and check that e.Position.Location.HorizontalAccuracy <= 350 (so under 350m) - but doing this with the datetime check as well can cause the phone to take a long time to get a position the lower you set the accuracy, so it may be best to get an initial position with the date check, and then continue to try get a better position with the Accuracy check. I also start the watcher as soon as the app starts to get faster results.

The other issue is MovementThreshold. If you do as I said above, it might still take a while before you get an accurate position, and you will likely experience the intermittent problem you mentioned where it does not fire the 2nd time (it does eventually, depending how long you wait - this can be minutes). The best thing I have found is to start the GeoCoordinateWatcher with the threshold set to 0. Once you have got an accurate position, stop the watcher, set the threshold to the actual one you want (eg 10), and then start it again. If you set this without stopping first, it will not use the new value.

<!-- language: c# -->
GeoPositionStatus = CurrentGeoDeviceStatus;
    static void geoCoordWatcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
    {
        CurrentGeoDeviceStatus = e.Status;
    }
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
    if (gpsReady && e.Position.Timestamp.DateTime.AddMinutes(5) > DateTime.Now)
    {
        latitude = e.Position.Location.Latitude.ToString("0.0000000000");
        longitude = e.Position.Location.Longitude.ToString("0.0000000000");
        locReady = true;
    }
}


It looks like the fix was to block it from using the first value and getting it from the second event instead:

bool gpsReady = false;
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
    if (gpsReady)
    {
        latitude = e.Position.Location.Latitude.ToString("0.0000000000");
        longitude = e.Position.Location.Longitude.ToString("0.0000000000");
        locReady = true;
    }
        gpsReady = true;
    }

I'm still baffled about why I don't get more events or why it fires an incorrect value first, but the above code seems to be working.

One note, for anyone else trying this, is that you might think getting the value in the StatusChanged event would work, like so:

case GeoPositionStatus.Ready:
    latitude = watcher.Position.Location.Latitude.ToString("0.0000000000");
    longitude = watcher.Position.Location.Longitude.ToString("0.0000000000");
    break;

I don't know why, but the above code seemed to work perfectly when I was running attached to the debugger and then frequently hung (that is, the event never fired and my UI seemed to hang) in practical use. I never managed to reproduced the issue while attached to the debugger.

UPDATE: It looks like this isn't working all of the time. In some cases it doesn't fire the second time and so my code never completes running. If anyone can provide more information around this that gets me closer to simply having the actual current location of the device without fail, I will definitely mark your answer as the answer. Thanks!

0

精彩评论

暂无评论...
验证码 换一张
取 消