Pull to refresh

Создание приложения для Windows Phone 7 от начала до конца. Часть 12. Изолированное хранилище: сохранение и загрузка данных

Development for Windows Phone *
Translation
Original author: Microsoft Developer Guidance team
Предыдущая часть

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

В этой части вы узнаете:
  • Как сохранять данные в изолированное хранилище.
  • Как загружать данные из изолированного хранилища.
  • Как удалять данные из изолированного хранилища.

Использование изолированного хранилища


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

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

Изолированное хранилище работает медленнее, чем хранящиеся в памяти словари, поэтому вы должны использовать его только для данных, которые потенциально требуют длительного хранения и для несериализуемых объектов, которые не поддерживаются словарями состояний (state dictionaries). Большинство классов являются сериализуемыми по умолчанию, но некоторые нет и, соответственно, требуют специальной обработки, как будет описано ниже. Например, несериализуемым является объект ImageSource, который представляет собой двоичный файл изображения, такой как JPG.

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

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

Изолированное хранилище обеспечивает две формы доступа:
  • Словарь состояний (state dictionary), который вы можете использовать для хранения пар вида ключ/значение, где значениями могут являться значения примитивных типов или сериализуемые объекты.
  • Виртуальный интерфейс файловой системы, который можно использовать для сохранения, загрузки и удаления файлов приложения.
Словарь состояний изолированного хранилища прост в использовании. Вы просто обращаетесь к нему через статическое свойство IsolatedStorageSettings.ApplicationSettings, а затем добавляете, удаляете или изменяете значения, как при работе с обычным словарём. Словарь автоматически выполняет работу по загрузке и сохранению значений в изолированное хранилище в подходящее время, хотя вы также можете переопределить это поведение.

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

Сохранение данных в изолированном хранилище


Для того, чтобы сохранить сериализуемый объект в изолированное хранилище с использованием словаря, вы просто присвиваете объект IsolatedStorageSettings.ApplicationSettings и указываете ключ. Затем вы вызываете метод IsolatedStorageSettings.Save. Вызов Save не требуется, потому что приложение будет автоматически сохранять все хранящиеся значения при выходе из приложения.

В следующем фрагменте кода показано, как сохранить объект Car (без учета его несериализуемого свойства Picture) в словаре. Метод CarDataStore.SaveCar присваивает значение свойства Car непосредственно словрю IsolatedStorageSettings.ApplicationSettings, используя константу CAR_KEY. Значение будет записано в изолированное хранилище, когда метод IsolatedStorageSettings.Save будет вызван в следующей строке.
  1. private const string CAR_PHOTO_FILE_NAME = "CarPhoto.jpg";
  2. private const string CAR_KEY = "FuelTracker.Car";
  3. private static readonly IsolatedStorageSettings appSettings =
  4.     IsolatedStorageSettings.ApplicationSettings;
  5.  
  6. public static void SaveCar(Action errorCallback)
  7. {
  8.     try
  9.     {
  10.         appSettings[CAR_KEY] = Car;
  11.         appSettings.Save();
  12.         SaveCarPhoto(CAR_PHOTO_FILE_NAME, Car.Picture, errorCallback);
  13.         DeleteTempCarPhoto();
  14.     }
  15.     catch (IsolatedStorageException)
  16.     {
  17.         errorCallback();
  18.     }
  19. }
* This source code was highlighted with Source Code Highlighter.

Вполне возможно, что нет доступного пространства в изолированном хранилище. В этом случае вызов метода Save выбросит exception (исключение). Важно обработать этот exception, но не имеет смысла делать это на уровне доступа к данным (in the data access layer). Вместо этого, как правило отображается предупреждение для пользователя. По этой причине метод SaveCar принимает делегат Action, который вызывается при возникновении исключения. Это позволяет вызывающему коду обрабатывать ошибки по-своему, без необходимости в собственном Try/Catch блоке или какой-либо зависимости от определенного типа исключения. Этот способ будет более подробно описан в части «Валидация вводимых данных».

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

Свойство Car.Picture представляет собой изображение автомобиля и является объектом типа BitmapImage. Поскольку тип BitmapImage не сериализуем, свойство Car.Picture не может быть сохранено в словаре IsolatedStorageSettings.ApplicationSettings, поэтому изображение будет рассматриваться отдельно. Однако, вы должны явно исключить свойство Picture из сериализации или вызов метода Save всегда будет бросать исключение. Чтобы исключить свойство из сериализации, вы должны применять IgnoreDataMemberAttribute к нему, как показано в следующем примере из Car.cs.
  1. [System.Runtime.Serialization.IgnoreDataMemberAttribute]
  2. public BitmapImage Picture
  3. {
  4.     get { return _picture; }
  5.     set
  6.     {
  7.         _picture = value;
  8.         NotifyPropertyChanged("Picture");
  9.     }
  10. }
* This source code was highlighted with Source Code Highlighter.

Чтобы сохранить файл в изолированное хранилище, используйте методы IsolatedStorageFile.CreateFile или IsolatedStorageFile.OpenFile. Также есть методы в IsolatedStorageFile для проверки, существует ли файл, и для создания каталогов.

Поскольку свойство Car.Picture не сериализуемо, оно сохраняется в виде файла в изолированном хранилище. Было бы здорово, если бы вы могли бы просто обратиться к выбранной фотографии по ссылке в медиа-библиотеке (media library) так, чтобы вам не нужно было сохранять его отдельно в изолированном хранилище. Однако, на момент написания статьи это не представлялось возможным. Дополнительная информация будет представлена в части «Доступ к фотографиям на Windows Phone».

В следующем коде показан метод SaveCarPhoto, который сохраняет изображение автомобиля как файл в каталоге в изолированном хранилище. Метод OpenFile используется для создания нового файла. Обратите внимание на использование метода Extensions.SaveJpeg. Этот вспомогательный метод упрощает преобразование BitmapImage в Stream.
  1. private const string CAR_PHOTO_DIR_NAME = "FuelTracker";
  2.  
  3. private static void SaveCarPhoto(string fileName, BitmapImage carPicture,
  4.     Action errorCallback)
  5. {
  6.     if (carPicture == null) return;
  7.     try
  8.     {
  9.         using (var store = IsolatedStorageFile.GetUserStoreForApplication())
  10.         {
  11.             var bitmap = new WriteableBitmap(carPicture);
  12.             var path = Path.Combine(CAR_PHOTO_DIR_NAME, fileName);
  13.  
  14.             if (!store.DirectoryExists(CAR_PHOTO_DIR_NAME))
  15.             {
  16.                 store.CreateDirectory(CAR_PHOTO_DIR_NAME);
  17.             }
  18.  
  19.             using (var stream = store.OpenFile(path, FileMode.Create))
  20.             {
  21.                 Extensions.SaveJpeg(bitmap, stream,
  22.                     bitmap.PixelWidth, bitmap.PixelHeight, 0, 100);
  23.             }
  24.         }
  25.     }
  26.     catch (IsolatedStorageException)
  27.     {
  28.         errorCallback();
  29.     }
  30. }
* This source code was highlighted with Source Code Highlighter.

На следующем изображении показано, как объект Car сохраняется в изолированном хранилище.

image

Чтение данных из изолированного хранения


Для чтения объекта из словаря в изолированном хранилище, вы просто указываете ключ объекта, который вы хотите. Следующий код демонстрирует, как извлечь значения из словаря в изолированном хранилище. Это код свойства CarDataStore.Car из части «Использование доступа к данным класса», но на этот раз он включает в себя детали, касающиеся хранения данных.
  1. private static Car car;
  2.  
  3. public static Car Car
  4. {
  5.     get
  6.     {
  7.         if (car == null)
  8.         {
  9.             if (appSettings.Contains(CAR_KEY))
  10.             {
  11.                 car = (Car)appSettings[CAR_KEY];
  12.                 car.Picture = GetCarPhoto(CAR_PHOTO_FILE_NAME);
  13.             }
  14.             else
  15.             {
  16.                 car = new Car()
  17.                 {
  18.                     FillupHistory = new ObservableCollection<Fillup>()
  19.                 };
  20.             }
  21.         }
  22.         return car;
  23.     }
  24.     set { car = value; }
  25. }
* This source code was highlighted with Source Code Highlighter.

В этом коде, если свойство Car еще не имеет значения, проверяется, содержит ли словарь значение для ключа указанного константой CAR_KEY. (Использование константы позволяет выбрать значение с помощью IntelliSense, что позволяет избежать возможность опечатки.) Если нет существующего значения, инициализируется новый экземпляр объекта Car и его свойство FillupHistory. В противном случае Car берется из словаря. Однако, следует отметить, что свойство Car.Picture имеет тип BitmapImage, который не является сериализуемым. Поскольку словарь IsolatedStorageSettings поддерживает только сериализуемые значения, свойство Picture должно обрабатываться отдельно.

Для чтения файлов из изолированного хранилища используйте метод IsolatedStorageFile.OpenFile. В следующем коде показан метод GetCarPhoto в приложении Fuel Tracker, получающий изображение из изолированного хранилища.
  1. private static BitmapImage GetCarPhoto(string fileName)
  2. {
  3.     using (IsolatedStorageFile store =
  4.         IsolatedStorageFile.GetUserStoreForApplication())
  5.     {
  6.         string path = Path.Combine(CAR_PHOTO_DIR_NAME, fileName);
  7.  
  8.         if (!store.FileExists(path)) return null;
  9.  
  10.         IsolatedStorageFileStream stream =
  11.             store.OpenFile(path, FileMode.Open);
  12.  
  13.         try
  14.         {
  15.             var image = new BitmapImage();
  16.             image.SetSource(stream);
  17.             return image;
  18.         }
  19.         finally
  20.         {
  21.             stream.Dispose();
  22.         }
  23.     }
  24. }
* This source code was highlighted with Source Code Highlighter.

Удаление данных из изолированного хранения


Для того, чтобы удалить значения из словаря состояний, вызовите метод IsolatedStorageSettings.Remove и укажите ключ. Затем вызовите метод IsolatedStorageSettings.Save для применения изменений. Для того, чтобы удалить файл из изолированного хранилища, вызовите метод IsolatedStorageFile.DeleteFile.

Следующий метод CarDataStore.DeleteCar демонстрирует, как удалить значение из словаря состояний и удалить файл.
  1. public static void DeleteCar()
  2. {
  3.     Car = null;
  4.     appSettings.Remove(CAR_KEY);
  5.     appSettings.Save();
  6.     DeleteCarPhoto();
  7.     DeleteTempCarPhoto();
  8. }
* This source code was highlighted with Source Code Highlighter.

Метод CarDataStore.DeleteCar сначала устанавливает свойство Car в null так, чтобы оно могло быть повторно инициализировано в случае обращения к нему в будущем. Затем запись CAR_KEY удаляется из словаря ApplicationSettings, и метод Save вызывается для того, чтобы применить изменения. Наконец, этот метод удаляет фотографии автомобиля из изолированного хранилища.

Рекомендация по проектированию интерфейса:
Действия приложения, которые перезаписывают или удаляют данные, или не могут быть обратимы должны иметь кнопку «Отмена».

Следующая часть
Tags:
Hubs:
Total votes 40: ↑21 and ↓19 +2
Views 3.1K
Comments Comments 1