Предыдущая часть

Когда пользователь покидает ваше приложения, оно дезактивируется. Если пользователь использует кнопку «Назад», чтобы вернуться к вашему приложению, вам необходимо восстановить приложение в соответствующее состояние.

В этой части вы узнаете:
  • Что такое tombstoning.
  • Как восстановить приложения после того, как оно было дезактивировано.
  • Когда выполнять другие действия в вашем приложении.

Обзор tombstoning


Ваше приложение может быть прервано и дезактивировано в любой момент, как правило, это происходит, когда пользователь переходит к другому приложению с помощью кнопки «Start». Когда это происходит, ваше приложение должно сохранить свое состояние так, чтобы оно могло быть восстановлено в случае возврата к нему. Однако, изолированное хранилище является слишком медленным для краткосрочного хранения данных о состоянии. Вместо этого, вы кэшируете данные, используя хранящиеся в памяти словари состоянии для того, чтобы быстро сохранить и загрузить данные.

Когда приложение дезактивируется, его процесс может быть остановлен с использованием процедуры, называемой tombstoning (tombstone — надгробная плита), которая сохранит записи приложения в памяти и свяжет их с вашими кэшированными данными о состоянии. Если пользователь переходит обратно в ваше приложение, операционная система перезапускает процесс приложения и передает ему обратно данные о состоянии.

Совет:
Когда работа приложения прерывается, а затем возобновляется, пользователи ожидают продолжения работы с того места, где она была прервана. По этой причине, вы всегда должны реализовывать поддержку tombstoning для любой страницы, которая может изменять свое состояние. Это относится к изменениям состояния настолько сложным, как обновление введённых пользователем данных, или настолько простым, как изменение текущего выделения в списке. Отсутствие поддержки tombstoning может привести к ухудшению юзабилити в лучшем случае и совершенно неожиданному поведению в худшем случае.

Сертификационное требование:
Ваше приложение не должно задерживать или препятствовать возможности пользователю совершить вызов, ответить на входящий вызов или завершить вызов.

Реализация поддержки tombstoning


Для того, чтобы использовать временный кэш, который сохраняется в течение tombstoning, выполните следующие действия:
  • Поместите данные о состоянии уровня приложения в свойство PhoneApplicationService.State в событии Deactivated и извлеките данные в обработчике события Activated.
  • Поместите данные о состоянии уровня страницы в свойство PhoneApplicationPage.State для каждой страницы в перегрузке метода OnNavigatedFrom и извлеките данные в перегрузке метода OnNavigatedTo.
Эти два свойства State представляют собой словари, в которых вы можете хранить пары вида значение/ключ, где значениями могут являться значения примитивных типов или сериализуемые объекты. Обратите внимание, что нет никакой гарантии, что дезактивированное приложение когда-либо будет повторно активировано, так что вы не должны использовать эти словари для хранения тех данных прилож��ния или пользователя, которые должны быть сохранены. Для длительного хранения используйте изолированное хранилище.

Совет по улучшению производительности:
Используйте словари состояний для восстановления состояния. Избегайте восстановления состояния из изолированного хранилища или из Интернета.

Приложение Fuel Tracker сохраняет временные состояния уровня страницы в процессе tombstoning, но не имеет данных о состоянии уровня приложений для сохранения. Каждая страница сохраняет данные о состоянии с своё свойство PhoneApplicationPage.State. Например, класс FillupPage содержит объект Fillup, привязанный к некоторым текстовым полям. Этот объект сохраняется на длительное хранение, только когда пользователь нажимает кнопку «Save». Однако, во время tombstoning страница помещает объект в словарь State (состояние) страницы наряду со значением, указывающим, вносил ли пользователь изменения в него, как показано в следующем фрагменте кода. (Реализации кнопки «Save» будет описана в части «Валидация вводимых данных».)
  1. private const string CURRENT_FILLUP_KEY = "CurrentFillup";
  2. private const string HAS_UNSAVED_CHANGES_KEY = "HasUnsavedChanges";
  3. private Fillup currentFillup;
  4. private bool hasUnsavedChanges;
  5.  
  6. protected override void OnNavigatedFrom(NavigationEventArgs e)
  7. {
  8.     base.OnNavigatedFrom(e);
  9.     if (cacheChanges)
  10.     {
  11.         CommitTextBoxes();
  12.         this.State[CURRENT_FILLUP_KEY] = currentFillup;
  13.         this.State[HAS_UNSAVED_CHANGES_KEY] = hasUnsavedChanges;
  14.     }
  15. }
  16.  
  17. protected override void OnNavigatedTo(NavigationEventArgs e)
  18. {
  19.     base.OnNavigatedTo(e);
  20.  
  21.     CarHeader.DataContext = CarDataStore.Car;
  22.  
  23.     DataContext = currentFillup =
  24.         State.ContainsKey(CURRENT_FILLUP_KEY) ?
  25.         (Fillup)this.State[CURRENT_FILLUP_KEY] :
  26.         new Fillup() { Date = DateTime.Now };
  27.  
  28.     hasUnsavedChanges = State.ContainsKey(HAS_UNSAVED_CHANGES_KEY) ?
  29.         (bool)State[HAS_UNSAVED_CHANGES_KEY] : false;
  30. }
* This source code was highlighted with Source Code Highlighter.

В этом коде перегруженный метод OnNavigatedFrom сначала проверяет, должен ли он кэшировать данные о состоянии. Класс FillupPage инициализирует поле cacheChanges в значение true, но устанавливает его в false всегда, когда происходит обычная навигация (то есть, когда пользователь нажимает кнопку «Save» или «Back»). Таким образом, страница кэширует данные только тогда, когда навигация происходит в результате дезактивации.

Если изменения были кэшированы, метод OnNavigatedFrom применяет значения текстовых полей к привязанному (bound) объекту (хранящемуся в поле currentFillup), а затем сохраняет значения currentFillup и hasUnsavedChanges в словарь State. Применение (committing) значения текстового поля необходимо, поскольку привязки данных обычно происходят, когда элемент управления теряет фокус, что не происходит автоматически, когда приложение дезактивируется.

Метод OnNavigatedTo устанавливает элемент CarHeader в свойство DataContext, а затем пытается получить хранящиеся значения из словаря State. Если значения представлены в словаре, они используются для установки свойства DataContext страницы в дополнение к полям currentFillup и hasUnsavedChanges. В противном случае, используются значения по умолчанию.

Данная реализация предоставляет базовую поддержку tombstoning, но не хранит каждый аспект состояния страницы. В частности, эта реализация не сохраняет значение, указывающее, какое текстовое поле находится в фокусе, а также не хранит позицию курсора и состояние выделения текстового поля в фокусе. Важность сохранения этой информации о состоянии зависит от приложения.

Совет:
При реализации поддержки tombstoning не забудьте тщательно её протестировать. Для этого перейдите к каждой странице (с помощью эмулятора или фактического устройства), нажмите кнопку «Start», а затем нажмите кнопку «Назад». Обязательно проверьте каждое состояние каждой странице вашего приложения и убедитесь, что реактивация всегда восстанавливает состояние так, как ожидалось.

Если вы тестируете поддержку tombstoning в эмуляторе в Visual Studio в режиме отладки, вы заметите, что отладчик иногда прерывает соединение, когда вы дезактивируете ваше приложение. В этом случае приложение будет казаться зависшим на «восстанавливающейся» странице, когда вы его повторно активируете. Вы можете решить эту проблему, просто перейдя в Visual Studio и нажав F5 снова. Приложение тогда будет перезагружено и повторно активировано.

Когда выполнять действия в приложении


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

Приложение Windows Phone запускается, когда пользователь нажимает на иконку или плитку приложения, и закрывается, когда пользователь нажимает кнопку «Назад» на первой странице приложения. Внешние события (например, при нажатии кнопки «Start») могут дезактивировать приложение в любое время, потенциально вызвав его tombstoning и заставляя его завершить работу. Повторная активация перезапускает приложения и дает ему возможность восстановить свое предыдущее состояние. Эти этапы запуска и завершения работы в жизненном цикле представлены в виде событий Launching, Activated, Closing и Deactivated класса PhoneApplicationService.

Как только приложение запущено, стартовая страница открывается автоматически, после чего пользователь может перейти на дополнительные страницы. Если приложение дезактивируется и повторно активируется, происходит переход к ранее активной страницы.

Когда приложение впервые переходит на страницу или переходит обратно на страницу после дезактивации и реактивации, происходит создание экземпляра страницы, вызывается его конструктор, а затем вызывается перегруженный метод OnNavigatedTo этой страницы, если они присутствуют. Незадолго до перехода к другой странице, выхода или дезактивации вызывается метод OnNavigatedFrom. Экземпляры страницы используются повторно, только если пользователь переходит обратно на посещенные ранее страницы и приложение не было дезактивировано после этого посещения. В этом случае приложение вызывает методы OnNavigatedTo и OnNavigatedFrom, как и раньше, но без вызова конструктора перед этим.

На следующем изображении показан общий жизненный цикл приложения и страницы.

image

Обычно вы будете использовать события Launching, Activated, Closing и Deactivated для инициализации и поддержки состояния приложения. Однако, когда эти события происходят, телефон все еще находится в процессе загрузки или выгрузки приложения, потенциально вызывая значительные задержки. Чтобы избежать увеличения этих задержек, вы всегда должны избегать трудоемких операций в обработчиках для этих событий.

Обычно вы будете использовать перегруженные методы OnNavigatedTo и OnNavigatedFrom страницы для инициализации состояния страницы и выполнения или запуска трудоёмких операций, таких, как загрузка и сохранение данных. Когда метод OnNavigatedTo вызывается, приложение и страницы уже закончили загрузку и доступны для использования. Когда метод OnNavigatedFrom вызывается, приложение и страницы еще не начали выгружаться.

Сертификационное требование:
Ваше приложение должно отрисовать свой первый экран в течение 5 секунд после запуска и начать реагировать на действия пользователя в течение 20 секунд.

Для удовлетворения первого требования, вы можете отображать заставку. Для удовлетворения второго требования, вы можете загружать данные только тогда, когда это необходимо, и запускать трудоёмкие операции асинхронно, возможно, с использованием BackgroundWorker. Однако, даже если вы используете фоновый поток, вы должны запускать его в перегруженном методе OnNavigatedTo, а не в обработчиках событий Launching или Activated, чтобы избежать увеличения времени запуска.

Сертификационное требование:
Когда приложение выгружается, оно также должно завершить все операции в течение 10 секунд по запросу на закрытие или дезактивацию, в противном случае будет выброшено исключение и приложение будет прервано. Для удовлетворения этого требования вы должны рассмотреть сохранение данных, как только они становятся доступны, или постепенное сохранение, если имеются большие объёмы данных.

Следующая часть