Статьи

Windows Phone 8 и непрерывное отслеживание местоположения в фоновом режиме (Часть 2)

В первой статье говорилось о том, как использовать новый Location API на Windows Phone 8. В нем я не говорил о фоновом отслеживании. Сегодня я изменю предыдущее решение, чтобы сделать это и регистрировать события в окне вывода, а также предотвращать обновление пользовательского интерфейса, пока приложение деактивировано.

Источник доступен здесь.

Начнем с сообщения ОС, что это приложение может отслеживать местоположение в фоновом режиме. Прежде всего, откройте файл WMAppManifest.xml в редакторе XML, щелкнув его правой кнопкой мыши и выбрав «Открыть с помощью».

Теперь мы заменим элемент DefaultTask следующим:

<DefaultTask Name="_default" NavigationPage="MainPage.xaml">
  <BackgroundExecution>
    <ExecutionType Name="LocationTracking" />
  </BackgroundExecution>
</DefaultTask>

Затем мы добавляем обработчик события RunningInBackground. В файле App.xaml обновите элемент shell: PhoneApplicationService, добавив RunningInBackground = ”Application_RunningInBackground”, чтобы он выглядел следующим образом:

<shell:PhoneApplicationService
    Launching="Application_Launching" Closing="Application_Closing"
    Activated="Application_Activated" Deactivated="Application_Deactivated"
    RunningInBackground="Application_RunningInBackground"/>

И добавьте пустой обработчик в App.xaml. Мы вернемся к этому обработчику чуть позже.

private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs args)
{
}

Нам нужен способ сообщить приложению, что оно работает в фоновом режиме. К App.xaml.cs нам нужно добавить свойство bool. Будет установлено статическое значение, поэтому к нему легко обратиться:

public static bool InBackground { get; set; }

Теперь мы добавим возможность просмотра состояния приложения в окне отладки. Для этого нам нужно добавить следующее с помощью страниц App.xaml.cs и MainPage.xaml.cs:

using System.Diagnostics;

После этого мы можем начать обновлять следующие 4 события со следующими значениями App.InBackground:

укротитель App.InBackground
Application_Launching ложный
Application_Activated ложный
Application_Deactivated правда
Application_RunningInBackground правда

Когда мы их установим, мы также добавим к каждому Debug.WriteLine, чтобы мы могли видеть, когда они запускаются. После этого они должны выглядеть так:

// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    Debug.WriteLine("Application Launching.");
    App.InBackground = false;
}
 
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    Debug.WriteLine("Application Activated.");
    App.InBackground = false;
}
 
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    Debug.WriteLine("Application Deactivated.");
    App.InBackground = true;
}
 
private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs args)
{
    Debug.WriteLine("Running in background.");
    App.InBackground = true;
}

Как видите, мы просто устанавливаем флаг, чтобы указать, работает ли приложение в фоновом режиме. Это может быть запеченный способ сделать это, но я сделал это таким образом.

Теперь мы можем обновить обработчик события geolocator_PositionChanged в файле MainPage.xaml.cs, чтобы зарегистрировать местоположение в окне отладки.

Debug.WriteLine(args.Position.Coordinate.Latitude.ToString("0.00000000") + " " + args.Position.Coordinate.Longitude.ToString("0.00000000"));

Последнее обновление заключается в использовании свойства App.InBackground в операторе if для отключения обновления пользовательского интерфейса. Мы используем Debug.WriteLine, чтобы сообщить нам местоположение в окне отладки.

if (App.InBackground == false)
{
    Dispatcher.BeginInvoke(() =>
    {
        Debug.WriteLine("UI Updated.");
        LatitudeTextBlock.Text = args.Position.Coordinate.Latitude.ToString("0.00000000");
        LongitudeTextBlock.Text = args.Position.Coordinate.Longitude.ToString("0.00000000");
    });
}
else
{
    Debug.WriteLine("UI NOT Updated.");
}

Теперь мы можем запустить решение и увидеть в окне отладки (в левом нижнем углу) событие запуска приложения:

Нажатие на кнопку запускает отслеживание, и пользовательский интерфейс обновляется, а местоположение записывается в окно отладки:

Нажатие на местоположение карты в эмуляторе обновит интерфейс и зарегистрирует местоположение:

Теперь, если мы нажмем кнопку «Пуск», мы увидим, что приложение переключилось на фоновую задачу и вошло в систему как «Запуск в фоновом режиме». Нажатие на местоположение карты показывает, что местоположение все еще регистрируется, но пользовательский интерфейс не обновляется:

При повторном открытии приложения отображается огонь события «Активировано приложением», и при щелчке новых местоположений на карте пользовательский интерфейс снова обновляется:

И, наконец, выход из приложения с помощью кнопки «Назад» запускает событие «Закрытие приложения» и нажатие на новые местоположения на карте больше не регистрируется, поскольку приложение больше не работает в фоновом режиме:

Существуют лучшие практики, которые необходимо использовать при реализации любых операций с интенсивным использованием батареи, и службы определения местоположения ничем не отличаются. Установка свойства DesiredAccuracy объекта Geolocator в PositionAccuracy.Default вместо PositionAccuracy.High и отключение Location Location, когда в этом нет необходимости, позволит сэкономить батарею. Увеличение свойства MovementThreshold приведет к тому, что событие PositionChanged будет запускаться реже, что также сэкономит батарею.

Еще одна вещь, которую нужно иметь в виду, планируя некоторые или все службы определения местоположения, может быть недоступна, и ваше приложение должно обрабатывать эту ситуацию, не создавая исключений.

Как видите, непрерывное отслеживание местоположения телефона в режиме реального времени с приложением в фоновом режиме просто реализовать в приложениях Windows Phone 8.