Опубликован: 22.12.2012 | Доступ: свободный | Студентов: 482 / 20 | Длительность: 07:20:00
Лекция 7:

Обзор архитектуры. Жизненный цикл приложения с архитектурой WinRT. Особенности архитектуры Использование инструментария СLR, .net. Методы программирования

< Лекция 6 || Лекция 7 || Лекция 8 >
Аннотация: В лекции приводится описание жизненного цикла приложения для Windows Store. Рассматриваются платформы для создания приложений для Windows Store.Перечислены пространства имен, предоставляемые в .NET for Windows Store apps.

Поскольку все приложения WinRT ориентируют пользователя на работу с контентом, то нет необходимости держать приложение в памяти, когда пользователь начал работу с другим приложением. С другой стороны, пользователь может в любой момент попытаться вернуться в приложение, поэтому производить его запуск с нуля тоже плохо. В связи с этим, Windows 8 приостанавливает работу приложения всякий раз, когда пользователь переключается на какое-то другое занятие, и держит это приложение в памяти, пока есть возможность. Как только пользователь возвращается в приложение, Windows 8 может либо активировать существующий в памяти экземпляр, либо же, если приложение было удалено, вызвать его снова. Именно поэтому у разработчика возникает ряд задач.

  1. Как только приложение переходит в состояние ожидания, данные, критичные для его возобновления, необходимо сохранить.
  2. В случае возобновления работы приложения из памяти необходимо определиться, нужно ли обновлять интерфейс приложения (так как за время его "сна" многое могло измениться) и восстанавливать сетевые подключения. Ведь если приложение оставалось в режиме сна слишком долго, проще обновить весь интерфейс с нуля.
  3. В случае возобновления работы приложения необходимо считать все сохраненные данные и запустить приложение с того состояния (если это возможно), на котором пользователь покинул приложение, либо же перезапустить приложение в штатном режиме.
 Жизненный цикл приложения WinRT

Рис. 6.1. Жизненный цикл приложения WinRT

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

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

Когда пользователь закрывает приложение нажатием клавиш Alt+F4 или жестом закрытия, приложение приостанавливается на 10 секунд и затем завершает работу.

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

Для успешного взаимодействия с пользователем необходимо восстанавливать первоначальный вид приложения, который был до приостановки. Это означает, что приложение должно сохранять любые введенные пользователем данные, измененные им параметры и т. д. Состояние приложения должно сохраняться при приостановке приложения на случай, если Windows завершит его. Только при таких условиях впоследствии можно восстановить состояние приложения.

В общем случае в приложении имеется два типа данных, которыми нужно управлять: данные приложения и данные сеанса.

Чтобы реализовать все вышеописанные механизмы, в классе Application (С#, C++) представлено несколько полезных событий. Давайте их рассмотрим.

  • Activated - событие генерируется в случае успешного запуска приложения. Теоретически, именно здесь необходимо определять, как именно было запущенно приложение, нужно ли восстанавливать состояние и др. На практике переопределить это событие нельзя, и тут существуют другие механизмы.
  • Suspending - это событие позволяет сохранить текущее состояние приложения. На это у приложения есть 5 секунд, после чего работа будет завершена в любом случае. Ничего сложного в рассматриваемом событии нет, достаточно определить обработчик и использовать локальное хранилище для сохранения данных.
  • Resuming - событие, которое дает шанс разработчику восстановить внешние ресурсы в случае, если приложение было запущено из памяти. Очевидно, что во время "сна" приложения сетевые соединения были разрушены, да и контент мог измениться. Тут нужно учитывать, что обработчик этого события не запускается в интерфейсном потоке, следовательно, нужно использовать Dispatcher.

Вернемся к событию Activated. Дело в том, что приложение может быть запущено по многим причинам: для использования приложения как источника поиска; в результате передачи какого-то файла данных; вследствие активации через FilePicker и др. Именно поэтому, чтобы облегчить жизнь разработчику, класс Application предлагает несколько методов перегрузки. Примерами таких методов могут служить OnFileActivated, OnSearchActivated, OnShareTargetActivated и др. Иными словами, если запуск Вашего приложения связан с инициацией какого-то контракта, то нужно попробовать найти метод, соответствующий этому контракту. Если метод для контракта не найден, то можно воспользоваться методом OnActivated, который получает в качестве параметров тип контракта.

async protected override void OnActivated(IActivatedEventArgs args)
{
switch (args.Kind)
{
case ActivationKind.CameraSettings:
. . . .
break;
case ActivationKind.ContactPicker:
. . . .
break;
case ActivationKind.PrintTaskSettings:
. . . .
break;
. . . .
}
base.OnActivated(args);
}

Если же не интересуют контракты, то рекомендуется перегружать метод OnLanched (он уже есть у Вас в коде) и именно тут делать проверки на состояние, из которого было запущено приложение, а также принимать решения, какие данные нужно обновлять и какую страницу делать основной. Параметр метода OnLauched содержит одно полезное свойство - PreviousExecutionState, которое позволяет определить, из какого состояния было запущено приложение.

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

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

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

Рассмотрим детально локальное хранение данных и временные данные. Роуминг данных будет рассмотрен далее.

Хранение данных локально

Существует два локального хранения данных:

  1. Хранить простые данные внутри реестра;
  2. Хранить данные внутри файлов.

Разумеется, что поскольку приложения WinRT работают внутри собственной "песочницы", то прямого доступа к реестру или файловой системе у них нет. По этой причине Windows Runtime предлагает специальный набор классов, который позволяет хранить данные в выделенном разделе реестра или папке, ассоциированной с конкретным пользователем.

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

  • ApplicationDataContainer - представляет собой контейнер, куда можно сохранять данные простых типов или данные, построенные на базе.
  • ApplicationDataCompositeValue. С каждым приложением ассоциируется контейнер по умолчанию, но можно и принудительно создавать вложенные контейнеры (аналог ключей и папок в реестре).
  • ApplicationDataCompositeValue - этот класс позволяет собрать сложный тип данных на основании нескольких простых. Фактически, указанный механизм облегчает группировку данных простых типов. Подобное можно сделать и с помощью вложенных контейнеров, но рассматриваемый класс более прост в использовании.

Перечисленные выше классы находятся в пространстве имен Windows.Storage и могут быть использованы без особых затруднений. Например, если необходимо получить контейнер по умолчанию или создать новый именованный контейнер, то можно применить следующий код.

ApplicationDataContainer current = ApplicationData.Current.LocalSettings;
ApplicationDataContainer named = current.CreateContainer(
"myContainer", ApplicationDataCreateDisposition.Always); 

Этот код получает ссылку на основной контейнер, ассоциированный с пользователем приложения, а затем создает вложенный контейнер. Имея ссылку на контейнер, можно приступить к сохранению простых данных.

При взаимодействии с реестром поддерживаются следующие типы данных: Boolean, Double, Int32, Int64, Single, String, UInt8, UInt32, UInt64.

Код ниже демонстрирует, как можно добавить новую пару ключ-значение в контейнер.

current.Values["myValue"] = 5;
current.Containers["myContainer"].Values["mySecondValue"] = "Hello"; 

Как видите, в примере присутствуют простые индексаторы, которые позволяют легко создать пару или получить значение по известному ключу.

Наконец, если требуется создать в контейнере комплексное (композитное) значение, то можно воспользоваться следующим кодом.

ApplicationDataCompositeValue composite =new ApplicationDataCompositeValue();
composite["fi rstVal"] = 1;
composite["secondVal"] = "Hello";
current.Values["compValue"] = composite; 

Гораздо интереснее работать с файлами. Для их хранения приложению также выделяется отдельный контейнер, с которым можно взаимодействовать при помощи класса StorageFolder.

StorageFolder current = ApplicationData.Current.LocalFolder; 

Созданный выше объект располагает множеством интересных методов.

  • CreateFileAsync - создает файл.
  • CreateFolderAsync - создает каталог.
  • DeleteAsync - удаляет объект (файл или каталог).
  • RenameAsync - позволяет выполнить переименование объекта.
  • GetFileAsync - позволяет вернуть ссылку на файл с указанным именем (объект типа StorageFile).
  • GetFilesAsync - возвращает список файлов, соответствующих запросу.
  • GetFolderAsync - возвращает указанный в параметрах каталог.
  • GetFoldersAsync - возвращает список каталогов, соответствующих запросу.
  • OpenStreamForReadAsync - открывает файл для чтения, позволяет вернуть объект типа Stream, представленный в платформе .NET Framework уже давно. Этот и следующий метод можно использовать для стандартного для .NET взаимодействия с файлами.
  • OpenStreamForWriteAsync - аналогичный предыдущему методу, но открывает файл для записи.
  • OpenAsync - позволяет открыть файл и обойтись только механизмами Windows Runtime, предоставляя механизмы работы с файлом через интерфейсы.

Рассмотрим небольшой пример, демонстрирующий создание файла в корневом каталоге приложения.

public async void WriteFile()
{
StorageFolder current = ApplicationData.Current.LocalFolder;
StorageFile fi le = await current.CreateFileAsync(
"hello.txt", CreationCollisionOption.ReplaceExisting);
IRandomAccessStream writeStream =
await fi le.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream outputStream = writeStream.GetOutputStreamAt(0);
DataWriter dataWriter = new DataWriter(outputStream);
dataWriter.WriteString("hello");
await dataWriter.StoreAsync();
outputStream.FlushAsync();
}

Как видите, код не очень простой и требует регулярного обращения к операторам await, да и сам метод был объявлен с модификатором async. Зато мы воспользовались только возможностями WinRT, не прибегая к механизмам .NET, а чтобы не активировать механизмы работы с массивом байтов, применили вспомогательный класс DataWriter. Этот класс может использовать поток, чтобы облегчить процедуры чтения и записи в файл.

Процедура чтения данных из файла выглядит аналогично.

public async void ReadFile()
{
StorageFolder current = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await current.GetFileAsync("hello.txt");
IRandomAccessStream readStream =
await sampleFile.OpenAsync(FileAccessMode.Read);
IInputStream inputStream = readStream.GetInputStreamAt(0);
DataReader dataReader = new DataReader(inputStream);
string myString = dataReader.ReadString((uint)readStream.Size);
}

Краткие итоги

В лекции приведены этапы жизненного цикла приложений для Windows Store. Приводится описание платформ для их разработки.

Вопросы

  1. Какие этапы включает жизненный цикл приложения для Windows Store?
  2. Почему при приостановке приложения оно должно оставаться в памяти?
  3. Что происходит с приложением после окончания работы с ним?
  4. Какими типами данных необходимо управлять при возобновлении работы приложения?
  5. Какие платформы используются для разработки приложений для Windows Store?
  6. В чем особенности платформы .NET Framework?
  7. В чем особенности созданий приложения WinRT с помощью C# или Visual Basic?
< Лекция 6 || Лекция 7 || Лекция 8 >