Lokalizacja  

Udostępnij na: Facebook

Autor: Marcin Kruszyński

Opublikowano: 2011-03-04

Urządzenia z Windows Phone 7 mają możliwość ustalenia swojego położenia geograficznego za pomocą serwisu lokalizacji. Dane są uzyskiwane z kilku różnych źródeł.

Po przeczytaniu tego artykułu będziesz:

  • wiedział, za pomocą jakich źródeł serwis lokalizacji ustala położenie,
  • znał architekturę serwisu lokalizacji i jego właściwości,
  • potrafił skorzystać z serwisu lokalizacji w swoich aplikacjach.

Wprowadzenie

Przy korzystaniu z serwisu lokalizacji powinniśmy być świadomi następujących uwarunkowań:

  • dane o położeniu mogą nie być dostępne przez cały czas,
  • ich dokładność zależy od rodzaju informacji dostarczanych przez sensory i od ustawień samego serwisu,
  • używanie serwisu lokalizacji, zwłaszcza przy większej dokładności, powoduje większe zużycie baterii,
  • inicjalizacja i uzyskanie pierwszego odczytu zajmuje trochę czasu,
  • użytkownik może wyłączyć serwis lokalizacji na telefonie w ustawieniach systemowych.

Architektura i właściwości

**Rys.*1.  Pozyskiwanie informacji o lokalizacji. *

Rysunek 1 pokazuje metody odczytywania położenia i związanych z nim danych stosowane przez serwis lokalizacji na telefonie z Windows Phone 7.

Architektura tego serwisu jest trójwarstwowa.

Pierwsza warstwa obejmuje sprzęt, w którego skład wchodzą:

  • wbudowany odbiornik GPS,
  • element odczytujący położenia stacji sieci komórkowej, z którymi komunikuje się telefon,
  • element pozyskujący informacje z połączeń Wi-Fi.

Wymagana przez aplikację dokładność i zużycie baterii są czynnikami, które wpływają na wybór źródeł danych. Wyznaczanie położenia za pomocą sieci komórkowej i Wi-Fi cechuje mniejsza dokładność i mniejsze zużycie energii. Natomiast odbiornik GPS pobiera więcej energii, ale ma większą precyzję.

Nad warstwą sprzętu znajduje się warstwa natywnego kodu i to w niej zawarta jest cała logika. Natywny kod komunikuje się bezpośrednio ze wszystkimi źródłami danych i podejmuje decyzję, którego z nich użyć w zależności od ich dostępności i wymaganego poziomu dokładności. Komunikuje się także z webserwisem firmy Microsoft w celu pobrania z bazy danych informacji związanych z lokalizacją.

Najwyższą warstwą jest warstwa kodu zarządzanego. Dzięki niej nasze aplikacje mogą uruchamiać i zatrzymywać serwis lokalizacji, ustawiać wymagany poziom dokładności oraz odbierać informacje o położeniu. Dostarczone API w Windows Phone 7 jest na ogół zgodne z API w .NET Framework 4.

Dobrą praktyką jest włączanie serwisu lokalizacji tylko wtedy, gdy jest wymagany. Warto używać też mniejszej dokładności ze względu na mniejsze zużycie energii. Z wysokiej dokładności korzystajmy tylko w sytuacjach, gdy jest to naprawdę potrzebne. W wielu przypadkach wystarczy jedynie znajomość miasta lub regionu, w którym znajduje się urządzenie.

Implementacja

Aplikacje mogą korzystać z serwisu lokalizacji opcjonalnie (np. obsługa zdjęć z geotagami), do jednokrotnego pobrania wartości lub wymagać go do poprawnego działania (np. geotracking). Są możliwe dwa podejścia – synchroniczne i asynchroniczne.

Zacznijmy od omówienia aplikacji korzystającej opcjonalnie z lokalizacji uruchamiającej serwis w sposób asynchroniczny. W tym przypadku wykonujemy następujące kroki:

  1. W projekcie dodajemy referencję do System.Device.dll.

  2. Tworzymy instancję klasy GeoCoordinateWatcher. W parametrze konstruktora przekazujemy wymagany poziom dokładności. Jeśli nie potrzebujemy wysokiej precyzji, wybieramy wartość GeoPositionAccuracy.Default.

    GeoCoordinateWatcher watcher;

    watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default); //Default, High

  3. Za pomocą propercji MovementThreshold określamy minimalną zmianę pozycji, przy której wywoływane jest zdarzenie PositionChanged.

    watcher.MovementThreshold = 20;

    Ponieważ GPS w urządzeniach mobilnych nie ma anteny, sensory są zazwyczaj bardzo czułe. Może to spowodować pewną ilość szumów w sygnale, np. wskutek odbić od powierzchni. Ustawienie propercji MovementThreshold na bardzo małą wartość może spowodować, że aplikacja będzie otrzymywać zdarzenia w wyniku szumu. Aby w sygnale były tylko znaczące zmiany pozycji, powinniśmy ustawić wartość progową na co najmniej 20 metrów. Aplikacja będzie wówczas zużywać też mniej energii. Wartość 0 metrów może być przydatna w przypadku aplikacji nawigacyjnych.

  4. Dodajemy handlery dla zdarzeń StatusChanged i PositionChanged:

    watcher.StatusChanged += newEventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);

    watcher.PositionChanged += newEventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

    Aplikacja powinna być przygotowana na niedostępność serwisu lokalizacji. Za pomocą handlera zdarzenia StatusChanged możemy wykryć, czy serwis lokalizacji jest gotowy i czy zawiera dane. Stan serwisu może przyjąć jedną z wartości typu wyliczeniowego: GeoPositionStatus: Ready, Disabled, Initializing i NoData. W przypadku wartości Disabled powinniśmy sprawdzić wartość propercji Permission w klasie GeoCoordinateWatcher. Jeśli tą wartością jest Denied, oznacza to, że użytkownik wyłączył serwis lokalizacji w swoim telefonie. Aplikacja może mu wtedy wyświetlić komunikat o zaistniałej sytuacji.

    void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
    {
        string currentStatus = e.Status.ToString();
        //...   
    }

    W handlerze zdarzenia PositionChanged otrzymujemy instancję klasy GeoCoordinate, która zawiera informacje na temat aktualnego położenia (szerokość i długość geograficzną, wysokość, kierunek, prędkość, dokładność w poziomie i w pionie). Niektóre z tych wartości mogą nie być dostępne (NaN). Zależy to od zastosowanej metody wyznaczania lokalizacji i wymaganej dokładności.

    void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
    {
        if (!e.Position.Location.IsUnknown)
        {
            double latitude = e.Position.Location.Latitude;
            double longitude = e.Position.Location.Longitude;
            double altitude = e.Position.Location.Altitude;
            double course = e.Position.Location.Course;
            double speed = e.Position.Location.Speed;
            double hAccuracy = e.Position.Location.HorizontalAccuracy;
            double vAccuracy = e.Position.Location.VerticalAccuracy;
            DateTimeOffset time = e.Position.Timestamp;
            //...
        }
    }

    Handlery do omówionych zdarzeń wywoływane są w innym wątku niż interfejs użytkownika. Musimy zadbać, aby kod aktualizujący UI był wywoływany w jego wątku.

  5. Uruchamiamy instancję serwisu lokalizacji za pomocą asynchronicznej metody Start:

    watcher.Start();

  6. Gdy nie potrzebujemy już otrzymywać informacji o zmianach położenia, należy wyłączyć serwis za pomocą metody Stop.

    Jeśli chcemy użyć serwisu lokalizacji do jednorazowego odczytu położenia, możemy pominąć obsługę zdarzenia PositionChanged, a w handlerze zdarzenia StatusChanged modyfikujemy kod:

    void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
    {
        if (e.Status == GeoPositionStatus.Ready)
        {
             double latitude = watcher.Position.Location.Latitude;
             double longitude = watcher.Position.Location.Longitude;
             //...
             watcher.Stop();
        }
    }

    Przy statusie Ready odczytujemy informacje na temat położenia, korzystając z propercji Position klasy GeoCoordinateWatcher. Następnie zatrzymujemy serwis.  

    Jeśli chcemy w naszym kodzie poczekać na pierwszą wartość udostępnioną przez serwis lokalizacji, stosujemy podejście synchroniczne. Zamiast metody Start wołamy metodę TryStart i w jej drugim parametrze podajemy timeout. Pierwszy parametr nie jest używany w obecnej wersji serwisu.

    watcher.TryStart(true, TimeSpan.FromSeconds(60));

    Nawet jeśli serwis jest w stanie pozyskiwać dane, jego inicjalizacja i pierwszy odczyt następuje zazwyczaj po 15 sekundach, ale może się też przedłużyć do 120 sekund. Przy małej dokładności serwis nie czeka na dane z GPS. Będzie więc na ogół szybciej, jeśli GPS nie został poprzednio aktywowany. Jeśli inne aplikacje korzystają z GPS, który dostarcza im już dane, ustalenie położenia z wysoką dokładnością powinno nastąpić tak samo szybko lub szybciej niż z niską dokładnością.

    Uruchomienie synchroniczne jest przydatne zarówno przy jednorazowym odczycie, jak i w aplikacjach wymagających lokalizacji do działania.

    Przy jednorazowym odczycie nie korzystamy ze zdarzeń, a po metodzie TryStart możemy umieścić następujący kod:

    if (watcher.Status == GeoPositionStatus.Ready && !watcher.Position.Location.IsUnknown)
    {
        double latitude = watcher.Position.Location.Latitude;
        double longitude = watcher.Position.Location.Longitude;
        //...   
    }

    watcher.Stop();

Klasa GeoCoordinateWatcher posiada propercję Status przyjmujacą jedną z wartości typu wyliczeniowego GeoPositionStatus. Przy wartości Ready możemy spróbować odczytać informacje na temat położenia.

W aplikacjach wymagających lokalizacji możemy sprawdzić, czy odczytywanie położenia zostało rozpoczęte w momencie ich startu. Jeśli metoda TryStart się powiodła i zwróciła wartość true, sprawdzamy, czy status serwisu ma wartość Ready. Reszta kodu aplikacji może być taka, jak w pierwszym przykładzie. Podobnie obsługujemy zdarzenia serwisu i zapewniamy możliwość jego wyłączenia.  

Kod używający lokalizacji nie działa na emulatorze. Nie mamy emulacji odbiornika GPS, nie możemy korzystać z Wi-Fi ani sieci komórkowej. Niemniej jednak możemy stworzyć imitację serwisu lokalizacji. Implementację takiej funkcjonalności ułatwia biblioteka Reactive Extensions (Rx). Szczegóły znajdziesz w dokumentacji na stronie How to: Use Reactive Extensions to Emulate and Filter Location Data for Windows Phone.

Położenie geograficzne bardzo często wizualizuje się za pomocą mapy. W Windows Phone 7 można to zrealizować za pomocą kontrolki Map, o której możesz przeczytać na stronie Bing Maps Silverlight Control for Windows Phone.

Podsumowanie

W tym artykule zapoznaliśmy się z serwisem lokalizacji, jego architekturą i właściwościami. Wiemy, za pomocą jakich metod może on wyznaczać położenie. Potrafimy korzystać z lokalizacji w aplikacjach różnego rodzaju.